pleasedontcode

# Torch Controller rev_03

Jan 23rd, 2026
17
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 41.04 KB | None | 0 0
  1. /********* Pleasedontcode.com **********
  2.  
  3.     Pleasedontcode thanks you for automatic code generation! Enjoy your code!
  4.  
  5.     - Terms and Conditions:
  6.     You have a non-exclusive, revocable, worldwide, royalty-free license
  7.     for personal and commercial use. Attribution is optional; modifications
  8.     are allowed, but you're responsible for code maintenance. We're not
  9.     liable for any loss or damage. For full terms,
  10.     please visit pleasedontcode.com/termsandconditions.
  11.  
  12.     - Project: # Torch Controller
  13.     - Source Code NOT compiled for: ESP32 DevKit V1
  14.     - Source Code created on: 2026-01-23 14:53:31
  15.  
  16. ********* Pleasedontcode.com **********/
  17.  
  18. /****** SYSTEM REQUIREMENTS *****/
  19. /****** SYSTEM REQUIREMENT 1 *****/
  20.     /* perbaiki coding proyek THC_ESP32 saya agar bisa di */
  21.     /* kontrol dan di monitor  melalui web server */
  22. /****** SYSTEM REQUIREMENT 2 *****/
  23.     /* Integrasikan web server HTTP pada ESP32 dengan */
  24.     /* JSON API untuk memantau tegangan busur 0-250V */
  25.     /* secara real-time, menampilkan status obor */
  26.     /* (UP/DOWN) pada LCD I2C, dan mengontrol program 3 */
  27.     /* parameter melalui encoder KY-040 lokal atau */
  28.     /* endpoint web. */
  29. /****** END SYSTEM REQUIREMENTS *****/
  30.  
  31.  
  32. // **TORCH HEIGHT CONTROL (THC) SYSTEM - ESP32 IMPLEMENTATION**
  33. // Complete system with web server, JSON API, LCD display, and rotary encoder control
  34.  
  35. #include <WiFi.h>
  36. #include <WebServer.h>
  37. #include <ArduinoJson.h>
  38. #include <EEPROM.h>
  39. #include <LiquidCrystal_I2C.h>
  40. #include <esp_timer.h>
  41.  
  42. // ========== HARDWARE PIN DEFINITIONS ==========
  43. // Arc Voltage ADC Input
  44. const int arcVoltagePin = 35;  // GPIO35 - ADC pin for arc voltage (0-250V mapped to 0-4095)
  45.  
  46. // Output Control Pins
  47. const int outputUpPin = 17;    // GPIO17 - Move torch UP
  48. const int outputOkPin = 16;    // GPIO16 - Arc OK signal
  49. const int outputDnPin = 5;     // GPIO5  - Move torch DOWN
  50.  
  51. // Rotary Encoder Pins
  52. const int pinCLK = 12;         // GPIO12 - Encoder CLK
  53. const int pinDT = 14;          // GPIO14 - Encoder DT
  54. const int pinSW = 27;          // GPIO27 - Encoder Switch (button)
  55.  
  56. // LCD I2C Configuration
  57. #define LCD_ADDR 0x27
  58. #define LCD_COLS 16
  59. #define LCD_ROWS 2
  60. LiquidCrystal_I2C lcd(LCD_ADDR, LCD_COLS, LCD_ROWS);
  61.  
  62. // ========== WIFI CONFIGURATION ==========
  63. const char* ssid = "ANLOG";
  64. const char* password = "serversatu1";
  65. WebServer server(80);
  66.  
  67. // ========== SYSTEM CONTROL VARIABLES ==========
  68. // Global timer handle
  69. esp_timer_handle_t timer_handle = NULL;
  70.  
  71. // THC Control Variables
  72. volatile bool Do = false;                    // Timer flag for 10ms interval
  73. unsigned int delayTime = 0;                  // Delay counter before arc OK
  74. unsigned int SetVx10 = 0;                    // Set voltage * 10 for comparison
  75.  
  76. // Arc Voltage Monitoring
  77. volatile unsigned int ArcV = 0;              // Arc voltage (0.1V units: 50-2500 = 50-250V)
  78. unsigned long lastArcVReading = 0;
  79. const int arcVoltageUpdateInterval = 100;   // Read arc voltage every 100ms
  80.  
  81. // LCD Display Management
  82. unsigned int LCDtime = 0;                    // LCD timeout counter
  83. unsigned int show = 0;                       // LCD refresh counter
  84. const unsigned int defaultLCDtime = 3000;   // Return to default display after 30 seconds
  85.  
  86. // Menu and UI Variables
  87. byte menu = 0;                               // Current menu state
  88. byte pos = 0;                                // Position in current menu
  89. volatile int encoderVal = 100;               // Encoder value (0-250)
  90. int oldValue = -1;                           // Previous encoder value for change detection
  91. unsigned long lastButtonPress = 0;           // Button debounce timer
  92.  
  93. // THC Parameters - Program Storage
  94. byte program = 1;                            // Currently loaded program (1-3)
  95. byte ParamItem = 4;                          // Number of parameters per program
  96.  
  97. // EEPROM Storage Addresses
  98. byte SetVa = 0;                              // Set Voltage address
  99. byte DTa = 1;                                // Delay Time address
  100. byte HySa = 2;                               // Hysteresis address
  101. byte StVa = 3;                               // Start Voltage address
  102. byte Param[4] = {100, 5, 80, 100};          // Parameter buffer [SetV, DT, HyS, StV]
  103.  
  104. // THC Parameter Values
  105. unsigned int SetV = 100;                     // Set Voltage (50-250V)
  106. unsigned int DT = 5;                         // Delay Time (0.1-20s in 0.1s units)
  107. unsigned int HyS = 80;                       // Hysteresis (1-99 in 0.1V units)
  108. unsigned int StV = 100;                      // Start Voltage (50-250V)
  109.  
  110. // Custom LCD Characters
  111. byte armsUpDn[8] = {
  112.   B00000, B00100, B01110, B00100,
  113.   B00000, B01110, B00000, B00000
  114. };
  115. byte customUp[8] = {
  116.   B00100, B01110, B10101, B00100,
  117.   B00100, B00100, B00100, B00000
  118. };
  119. byte customDown[8] = {
  120.   B00100, B00100, B00100, B00100,
  121.   B10101, B01110, B00100, B00000
  122. };
  123.  
  124. // ========== ENCODER INTERRUPT HANDLING ==========
  125. // Interrupt handler for rotary encoder rotation
  126. void IRAM_ATTR isrEncoder() {
  127.   int currentClkState = digitalRead(pinCLK);
  128.   int dtState = digitalRead(pinDT);
  129.  
  130.   if (currentClkState == LOW) {
  131.     if (dtState != currentClkState) {
  132.       encoderVal++;  // Clockwise
  133.     } else {
  134.       encoderVal--;  // Counter-clockwise
  135.     }
  136.   }
  137. }
  138.  
  139. // ========== TIMER CALLBACK ==========
  140. // Called every 10ms by the ESP timer
  141. void onTimerCallback(void* arg) {
  142.   Do = true;
  143. }
  144.  
  145. // ========== ARC VOLTAGE READING ==========
  146. // Read and process arc voltage from ADC
  147. void readArcVoltage() {
  148.   unsigned long now = millis();
  149.   if (now - lastArcVReading >= arcVoltageUpdateInterval) {
  150.     lastArcVReading = now;
  151.    
  152.     // Read ADC value (0-4095) and convert to voltage units (0.1V)
  153.     // Assuming 250V = 4095 ADC counts
  154.     int rawValue = analogRead(arcVoltagePin);
  155.     ArcV = (rawValue * 250 * 10) / 4095;  // Convert to 0.1V units
  156.    
  157.     // Constrain to valid range
  158.     if (ArcV < 0) ArcV = 0;
  159.     if (ArcV > 2500) ArcV = 2500;
  160.   }
  161. }
  162.  
  163. // ========== THC CONTROL ALGORITHM ==========
  164. void Setup_THC() {
  165.   // Initialize torch control output pins
  166.   pinMode(outputUpPin, OUTPUT);
  167.   pinMode(outputOkPin, OUTPUT);
  168.   pinMode(outputDnPin, OUTPUT);
  169.  
  170.   // Set all outputs to LOW (off)
  171.   digitalWrite(outputUpPin, LOW);
  172.   digitalWrite(outputOkPin, LOW);
  173.   digitalWrite(outputDnPin, LOW);
  174. }
  175.  
  176. void doTHC() {
  177.   // Main THC control algorithm - called every 10ms from timer callback
  178.   if (Do) {
  179.     Do = false;
  180.    
  181.     // Increment display refresh counters
  182.     LCDtime++;
  183.     show++;
  184.    
  185.     // Auto-return to default display after timeout
  186.     if (LCDtime > defaultLCDtime) {
  187.       menu = 0;
  188.       pos = 0;
  189.       LCDtime = 0;
  190.       encoderVal = SetV;
  191.     }
  192.    
  193.     // Arc voltage range check (500-2500 in 0.1V units = 50-250V)
  194.     if ((500 < ArcV) && (ArcV < 2500)) {
  195.       // Arc voltage is in valid range
  196.      
  197.       // Wait for arc to stabilize - count until delay time reached
  198.       if (ArcV > StV * 10) {
  199.         delayTime++;
  200.       }
  201.      
  202.       // Only control torch height after delay time expires
  203.       if (delayTime >= DT * 10) {
  204.         SetVx10 = SetV * 10;  // Convert SetV to same units as ArcV
  205.         delayTime = DT * 10;  // Prevent overflow - hold at max
  206.        
  207.         // Signal that arc is OK for cutting
  208.         digitalWrite(outputOkPin, HIGH);
  209.        
  210.         // Compare measured arc voltage with setpoint and hysteresis band
  211.         if (ArcV >= SetVx10 + HyS) {
  212.           // Arc voltage too high - move torch DOWN to reduce voltage
  213.           digitalWrite(outputUpPin, LOW);
  214.           digitalWrite(outputDnPin, HIGH);
  215.         }
  216.         else if (ArcV <= SetVx10 - HyS) {
  217.           // Arc voltage too low - move torch UP to increase voltage
  218.           digitalWrite(outputDnPin, LOW);
  219.           digitalWrite(outputUpPin, HIGH);
  220.         }
  221.         else {
  222.           // Arc voltage within hysteresis band - STOP moving torch
  223.           digitalWrite(outputUpPin, LOW);
  224.           digitalWrite(outputDnPin, LOW);
  225.         }
  226.       }
  227.     }
  228.     // Arc voltage out of range or arc lost
  229.     else if (menu != 12) {  // Don't turn off if in test mode
  230.       // Reset delay timer
  231.       delayTime = 0;
  232.      
  233.       // Turn off all outputs - arc is lost
  234.       digitalWrite(outputUpPin, LOW);
  235.       digitalWrite(outputOkPin, LOW);
  236.       digitalWrite(outputDnPin, LOW);
  237.     }
  238.   }
  239. }
  240.  
  241. // ========== LCD INITIALIZATION ==========
  242. void Setup_LCD() {
  243.   // Initialize LCD with I2C
  244.   lcd.init();
  245.   lcd.backlight();
  246.  
  247.   // Create custom characters
  248.   lcd.createChar(0, armsUpDn);
  249.   lcd.createChar(1, customUp);
  250.   lcd.createChar(2, customDown);
  251.  
  252.   // Display splash screen
  253.   lcd.setCursor(1, 0);
  254.   lcd.print("MEHMET IBRAHIM");
  255.   lcd.setCursor(3, 1);
  256.   lcd.print("Plasma THC");
  257.   delay(1500);
  258.   lcd.clear();
  259. }
  260.  
  261. // ========== LCD DISPLAY FUNCTIONS ==========
  262. void doLCD() {
  263.   if (show >= 2) {
  264.     show = 0;
  265.     switch (menu) {
  266.       case 0:
  267.         doLCDDefault();
  268.         break;
  269.       case 1:
  270.         doLCDMenu();
  271.         break;
  272.       case 11:
  273.         doLCDMenuSetup();
  274.         break;
  275.       case 111:
  276.         doLCDDelayTime();
  277.         break;
  278.       case 112:
  279.         doLCDHysteresis();
  280.         break;
  281.       case 113:
  282.         doLCDStartVoltage();
  283.         break;
  284.       case 114:
  285.         doLCDLoadDefault();
  286.         break;
  287.       case 12:
  288.         doLCDTest();
  289.         break;
  290.       case 115:
  291.         doTestUp();
  292.         break;
  293.       case 116:
  294.         doTestDown();
  295.         break;
  296.       case 13:
  297.         doLCDProgramSelect();
  298.         break;
  299.       case 121:
  300.         doProgramSet(1);
  301.         break;
  302.       case 122:
  303.         doProgramSet(2);
  304.         break;
  305.       case 123:
  306.         doProgramSet(3);
  307.         break;
  308.       default:
  309.         doLCDDefault();
  310.     }
  311.   }
  312. }
  313.  
  314. // Default display showing current SetV and ArcV
  315. void doLCDDefault() {
  316.   if (encoderVal < 0) encoderVal = 0;
  317.   else if (encoderVal > 250) encoderVal = 250;
  318.   SetV = encoderVal;
  319.   if (SetV != oldValue) {
  320.     SaveData(SetVa, SetV);
  321.     oldValue = SetV;
  322.   }
  323.   lcd.setCursor(0, 0);
  324.   lcd.print("P ");
  325.  
  326.   if (digitalRead(outputUpPin) == HIGH) {
  327.     lcd.write(1);  // Up arrow
  328.   } else {
  329.     lcd.print(" ");
  330.   }
  331.   lcd.print(" ");
  332.   lcd.setCursor(4, 0);
  333.   lcd.print("Set.V: ");
  334.   lcd.print(SetV);
  335.   lcd.print("   ");
  336.  
  337.   lcd.setCursor(0, 1);
  338.   lcd.print(program);
  339.   lcd.print(" ");
  340.   if (digitalRead(outputDnPin) == HIGH) {
  341.     lcd.write(2);  // Down arrow
  342.   } else {
  343.     lcd.print(" ");
  344.   }
  345.   lcd.print(" ");
  346.   lcd.setCursor(4, 1);
  347.   lcd.print("Arc.V: ");
  348.   lcd.print(ArcV / 10);
  349.   lcd.print("   ");
  350. }
  351.  
  352. // Main menu navigation
  353. void doLCDMenu() {
  354.   if (encoderVal < 0) encoderVal = 3;
  355.   pos = encoderVal % 4;
  356.   switch (pos) {
  357.     case 0:
  358.       lcd.setCursor(0, 0);
  359.       lcd.print("> Exit          ");
  360.       lcd.setCursor(0, 1);
  361.       lcd.print("  Program       ");
  362.       break;
  363.     case 1:
  364.       lcd.setCursor(0, 0);
  365.       lcd.print("> Program       ");
  366.       lcd.setCursor(0, 1);
  367.       lcd.print("  Setup         ");
  368.       break;
  369.     case 2:
  370.       lcd.setCursor(0, 0);
  371.       lcd.print("> Setup         ");
  372.       lcd.setCursor(0, 1);
  373.       lcd.print("  Test          ");
  374.       break;
  375.     case 3:
  376.       lcd.setCursor(0, 0);
  377.       lcd.print("> Test          ");
  378.       lcd.setCursor(0, 1);
  379.       lcd.print("  Exit       ");
  380.       break;
  381.   }
  382. }
  383.  
  384. // Program selection menu
  385. void doLCDProgramSelect() {
  386.   if (encoderVal < 0) encoderVal = 3;
  387.   pos = abs(encoderVal % 4);
  388.   switch (pos) {
  389.     case 0:
  390.       lcd.setCursor(0, 0);
  391.       lcd.print(">> Exit         ");
  392.       lcd.setCursor(0, 1);
  393.       lcd.print("   Load Prog: 1 ");
  394.       break;
  395.     case 1:
  396.       lcd.setCursor(0, 0);
  397.       lcd.print(">> Load Prog: 1 ");
  398.       lcd.setCursor(0, 1);
  399.       lcd.print("   Load Prog: 2 ");
  400.       break;
  401.     case 2:
  402.       lcd.setCursor(0, 0);
  403.       lcd.print(">> Load Prog: 2 ");
  404.       lcd.setCursor(0, 1);
  405.       lcd.print("   Load Prog: 3 ");
  406.       break;
  407.     case 3:
  408.       lcd.setCursor(0, 0);
  409.       lcd.print(">> Load Prog: 3 ");
  410.       lcd.setCursor(0, 1);
  411.       lcd.print("   Exit         ");
  412.       break;
  413.   }
  414. }
  415.  
  416. // Setup menu
  417. void doLCDMenuSetup() {
  418.   if (encoderVal < 0) encoderVal = 4;
  419.   pos = abs(encoderVal % 5);
  420.   switch (pos) {
  421.     case 0:
  422.       lcd.setCursor(0, 0);
  423.       lcd.print(">> Exit         ");
  424.       lcd.setCursor(0, 1);
  425.       lcd.print("   Delay Time   ");
  426.       break;
  427.     case 1:
  428.       lcd.setCursor(0, 0);
  429.       lcd.print(">> Delay Time   ");
  430.       lcd.setCursor(0, 1);
  431.       lcd.print("   Hysteresis   ");
  432.       break;
  433.     case 2:
  434.       lcd.setCursor(0, 0);
  435.       lcd.print(">> Hysteresis   ");
  436.       lcd.setCursor(0, 1);
  437.       lcd.print("   Start Voltage");
  438.       break;
  439.     case 3:
  440.       lcd.setCursor(0, 0);
  441.       lcd.print(">> Start Voltage");
  442.       lcd.setCursor(0, 1);
  443.       lcd.print("   Load Default ");
  444.       break;
  445.     case 4:
  446.       lcd.setCursor(0, 0);
  447.       lcd.print(">> Load Default ");
  448.       lcd.setCursor(0, 1);
  449.       lcd.print("   Exit         ");
  450.       break;
  451.   }
  452. }
  453.  
  454. // Test mode menu
  455. void doLCDTest() {
  456.   if (encoderVal < 0) encoderVal = 2;
  457.   pos = abs(encoderVal % 3);
  458.   switch (pos) {
  459.     case 0:
  460.       lcd.setCursor(0, 0);
  461.       lcd.print("Test > Exit     ");
  462.       lcd.setCursor(0, 1);
  463.       lcd.print("       Torch Up ");
  464.       digitalWrite(outputDnPin, LOW);
  465.       digitalWrite(outputUpPin, LOW);
  466.       digitalWrite(outputOkPin, LOW);
  467.       break;
  468.     case 1:
  469.       lcd.setCursor(0, 0);
  470.       lcd.print("Test > Torch Up ");
  471.       lcd.setCursor(0, 1);
  472.       lcd.print("       Torch Dn ");
  473.       if (digitalRead(outputOkPin) == LOW) LCDtime = 0;
  474.       if (LCDtime >= 200) {  // 100 LCDtime = 1s
  475.         digitalWrite(outputDnPin, LOW);
  476.         digitalWrite(outputUpPin, LOW);
  477.         digitalWrite(outputOkPin, LOW);
  478.       }
  479.       break;
  480.     case 2:
  481.       lcd.setCursor(0, 0);
  482.       lcd.print("Test > Torch Dn ");
  483.       lcd.setCursor(0, 1);
  484.       lcd.print("       Exit     ");
  485.       if (digitalRead(outputOkPin) == LOW) LCDtime = 0;
  486.       if (LCDtime >= 200) {
  487.         digitalWrite(outputDnPin, LOW);
  488.         digitalWrite(outputUpPin, LOW);
  489.         digitalWrite(outputOkPin, LOW);
  490.       }
  491.       break;
  492.   }
  493. }
  494.  
  495. // Test torch UP function
  496. void doTestUp() {
  497.   digitalWrite(outputDnPin, LOW);
  498.   digitalWrite(outputUpPin, HIGH);
  499.   digitalWrite(outputOkPin, HIGH);
  500.   LCDtime = 0;
  501.   menu = 12;
  502.   encoderVal = 1;
  503. }
  504.  
  505. // Test torch DOWN function
  506. void doTestDown() {
  507.   digitalWrite(outputDnPin, HIGH);
  508.   digitalWrite(outputUpPin, LOW);
  509.   digitalWrite(outputOkPin, HIGH);
  510.   LCDtime = 0;
  511.   menu = 12;
  512.   encoderVal = 2;
  513. }
  514.  
  515. // Set Delay Time parameter
  516. void doLCDDelayTime() {
  517.   if (encoderVal < 1) encoderVal = 1;
  518.   else if (encoderVal > 200) encoderVal = 200;
  519.  
  520.   DT = encoderVal;
  521.   if (DT != oldValue) {
  522.     SaveData(DTa, DT);
  523.     oldValue = DT;
  524.     LCDtime = 0;
  525.   }
  526.  
  527.   double x = DT / 10.00;
  528.   lcd.setCursor(0, 0);
  529.   lcd.print("Set > Delay Time");
  530.   lcd.setCursor(0, 1);
  531.   lcd.print("     : ");
  532.   lcd.print(x, 1);
  533.   lcd.print(" s       ");
  534. }
  535.  
  536. // Set Hysteresis parameter
  537. void doLCDHysteresis() {
  538.   if (encoderVal < 1) encoderVal = 1;
  539.   else if (encoderVal > 99) encoderVal = 99;
  540.  
  541.   HyS = encoderVal;
  542.   if (HyS != oldValue) {
  543.     SaveData(HySa, HyS);
  544.     oldValue = HyS;
  545.     LCDtime = 0;
  546.   }
  547.  
  548.   double x = HyS / 10.00;
  549.   lcd.setCursor(0, 0);
  550.   lcd.print("Set > Hysteresis");
  551.   lcd.setCursor(0, 1);
  552.   lcd.print("     :");
  553.   lcd.write(0);
  554.   lcd.print(x, 1);
  555.   lcd.print(" V       ");
  556. }
  557.  
  558. // Set Start Voltage parameter
  559. void doLCDStartVoltage() {
  560.   if (encoderVal < 50) encoderVal = 50;
  561.   else if (encoderVal > 250) encoderVal = 250;
  562.  
  563.   StV = encoderVal;
  564.   if (StV != oldValue) {
  565.     SaveData(StVa, StV);
  566.     oldValue = StV;
  567.     LCDtime = 0;
  568.   }
  569.  
  570.   lcd.setCursor(0, 0);
  571.   lcd.print("Set > Start Volt");
  572.   lcd.setCursor(0, 1);
  573.   lcd.print("     : ");
  574.   lcd.print(StV);
  575.   lcd.print(" V       ");
  576. }
  577.  
  578. // Load default parameters
  579. void doLCDLoadDefault() {
  580.   Default();
  581.  
  582.   for (byte i = 0; i < 100; i++) {
  583.     lcd.setCursor(0, 0);
  584.     lcd.print("     Default    ");
  585.     lcd.setCursor(0, 1);
  586.     lcd.print("Load   ");
  587.     lcd.print(i);
  588.     lcd.print(" ");
  589.     lcd.print("%");
  590.     lcd.print("        ");
  591.     delay(5);
  592.   }
  593.   lcd.setCursor(0, 0);
  594.   lcd.print("Default:  DONE  ");
  595.   lcd.setCursor(0, 1);
  596.   lcd.print("Please Restart  ");
  597.   exit(0);
  598. }
  599.  
  600. // Load program parameters
  601. void doProgramSet(int prg) {
  602.   if (prg == 1) {
  603.     SetVa = 0;
  604.     DTa = 1;
  605.     HySa = 2;
  606.     StVa = 3;
  607.     ReadDataProg_1();
  608.   } else if (prg == 2) {
  609.     SetVa = 4;
  610.     DTa = 5;
  611.     HySa = 6;
  612.     StVa = 7;
  613.     ReadDataProg_2();
  614.   } else {
  615.     SetVa = 8;
  616.     DTa = 9;
  617.     HySa = 10;
  618.     StVa = 11;
  619.     ReadDataProg_3();
  620.   }
  621.  
  622.   SaveData(100, prg);
  623.   program = prg;
  624.  
  625.   SetV = Param[0];
  626.   DT = Param[1];
  627.   HyS = Param[2];
  628.   StV = Param[3];
  629.   encoderVal = SetV;
  630.   menu = 0;
  631. }
  632.  
  633. // ========== EEPROM MANAGEMENT ==========
  634. void Default() {
  635.   // Initialize all programs with default values
  636.   SetVa = 0;
  637.   DTa = 1;
  638.   HySa = 2;
  639.   StVa = 3;
  640.  
  641.   SetV = 100;
  642.   DT = 5;
  643.   HyS = 80;
  644.   StV = 100;
  645.  
  646.   // Program 1
  647.   EEPROM.write(0, SetV);
  648.   EEPROM.write(1, DT);
  649.   EEPROM.write(2, HyS);
  650.   EEPROM.write(3, StV);
  651.  
  652.   // Program 2
  653.   EEPROM.write(4, SetV);
  654.   EEPROM.write(5, DT);
  655.   EEPROM.write(6, HyS);
  656.   EEPROM.write(7, StV);
  657.  
  658.   // Program 3
  659.   EEPROM.write(8, SetV);
  660.   EEPROM.write(9, DT);
  661.   EEPROM.write(10, HyS);
  662.   EEPROM.write(11, StV);
  663.  
  664.   EEPROM.write(12, 1);  // Default program is 1
  665.  
  666.   EEPROM.commit();
  667. }
  668.  
  669. void ReadProg() {
  670.   program = EEPROM.read(12);
  671. }
  672.  
  673. void ReadDataProg_1() {
  674.   // Param Address: 0, 1, 2, 3
  675.   for (int j = 0; j < ParamItem; j++) {
  676.     Param[j] = EEPROM.read(j);
  677.   }
  678. }
  679.  
  680. void ReadDataProg_2() {
  681.   // Param Address: 4, 5, 6, 7
  682.   for (int j = 0; j < ParamItem; j++) {
  683.     Param[j] = EEPROM.read(j + 4);
  684.   }
  685. }
  686.  
  687. void ReadDataProg_3() {
  688.   // Param Address: 8, 9, 10, 11
  689.   for (int j = 0; j < ParamItem; j++) {
  690.     Param[j] = EEPROM.read(j + 8);
  691.   }
  692. }
  693.  
  694. void SaveData(int add, int value) {
  695.   EEPROM.write(add, value);
  696.   EEPROM.commit();
  697. }
  698.  
  699. // ========== TIMER SETUP ==========
  700. void Setup_Timer() {
  701.   // Create periodic timer configuration
  702.   esp_timer_create_args_t timer_args = {
  703.     .callback = &onTimerCallback,
  704.     .name = "THC_Timer_10ms"
  705.   };
  706.  
  707.   // Create the timer
  708.   ESP_ERROR_CHECK(esp_timer_create(&timer_args, &timer_handle));
  709.  
  710.   // Start the timer - repeats every 10,000 microseconds (10ms)
  711.   ESP_ERROR_CHECK(esp_timer_start_periodic(timer_handle, 10000));
  712. }
  713.  
  714. // ========== ENCODER MENU CONTROL ==========
  715. void handleEncoderButton() {
  716.   if (digitalRead(pinSW) == LOW) {
  717.     if (millis() - lastButtonPress > 200) {  // Debounce 200ms
  718.       lastButtonPress = millis();
  719.      
  720.       // Handle button press based on current menu
  721.       switch (menu) {
  722.         case 0:  // Default display - press to enter main menu
  723.           menu = 1;
  724.           encoderVal = 0;
  725.           LCDtime = 0;
  726.           break;
  727.         case 1:  // Main menu
  728.           switch (pos) {
  729.             case 0:  // Exit
  730.               menu = 0;
  731.               encoderVal = SetV;
  732.               break;
  733.             case 1:  // Program
  734.               menu = 13;
  735.               encoderVal = 0;
  736.               break;
  737.             case 2:  // Setup
  738.               menu = 11;
  739.               encoderVal = 0;
  740.               break;
  741.             case 3:  // Test
  742.               menu = 12;
  743.               encoderVal = 0;
  744.               break;
  745.           }
  746.           break;
  747.         case 11:  // Setup menu
  748.           switch (pos) {
  749.             case 0:  // Exit
  750.               menu = 1;
  751.               encoderVal = 1;
  752.               break;
  753.             case 1:  // Delay Time
  754.               menu = 111;
  755.               encoderVal = DT;
  756.               oldValue = -1;
  757.               break;
  758.             case 2:  // Hysteresis
  759.               menu = 112;
  760.               encoderVal = HyS;
  761.               oldValue = -1;
  762.               break;
  763.             case 3:  // Start Voltage
  764.               menu = 113;
  765.               encoderVal = StV;
  766.               oldValue = -1;
  767.               break;
  768.             case 4:  // Load Default
  769.               menu = 114;
  770.               break;
  771.           }
  772.           break;
  773.         case 13:  // Program select
  774.           switch (pos) {
  775.             case 0:  // Exit
  776.               menu = 1;
  777.               encoderVal = 1;
  778.               break;
  779.             case 1:  // Program 1
  780.               menu = 121;
  781.               doProgramSet(1);
  782.               break;
  783.             case 2:  // Program 2
  784.               menu = 122;
  785.               doProgramSet(2);
  786.               break;
  787.             case 3:  // Program 3
  788.               menu = 123;
  789.               doProgramSet(3);
  790.               break;
  791.           }
  792.           break;
  793.         case 12:  // Test mode
  794.           switch (pos) {
  795.             case 0:  // Exit
  796.               menu = 1;
  797.               encoderVal = 3;
  798.               break;
  799.             case 1:  // Torch Up
  800.               menu = 115;
  801.               break;
  802.             case 2:  // Torch Down
  803.               menu = 116;
  804.               break;
  805.           }
  806.           break;
  807.       }
  808.     }
  809.   }
  810. }
  811.  
  812. // ========== WEB SERVER SETUP ==========
  813. void Setup_WebServer() {
  814.   // Initialize WiFi
  815.   WiFi.mode(WIFI_STA);
  816.   WiFi.begin(ssid, password);
  817.  
  818.   // Wait for WiFi connection
  819.   int attempts = 0;
  820.   while (WiFi.status() != WL_CONNECTED && attempts < 20) {
  821.     delay(500);
  822.     Serial.print(".");
  823.     attempts++;
  824.   }
  825.  
  826.   if (WiFi.status() == WL_CONNECTED) {
  827.     Serial.println("");
  828.     Serial.println("WiFi connected");
  829.     Serial.print("IP address: ");
  830.     Serial.println(WiFi.localIP());
  831.   } else {
  832.     Serial.println("WiFi connection failed!");
  833.   }
  834.  
  835.   // Define web server routes
  836.   server.on("/", HTTP_GET, handleWebRoot);
  837.   server.on("/api/status", HTTP_GET, handleAPIStatus);
  838.   server.on("/api/parameters", HTTP_GET, handleAPIParameters);
  839.   server.on("/api/parameters", HTTP_POST, handleAPISetParameters);
  840.   server.on("/api/program", HTTP_GET, handleAPIGetProgram);
  841.   server.on("/api/program", HTTP_POST, handleAPISetProgram);
  842.   server.on("/api/control", HTTP_POST, handleAPIControl);
  843.   server.on("/api/arcvoltage", HTTP_GET, handleAPIArcVoltage);
  844.  
  845.   // Start the server
  846.   server.begin();
  847.   Serial.println("Web server started");
  848. }
  849.  
  850. // ========== WEB HANDLERS ==========
  851. void handleWebRoot() {
  852.   // Serve HTML dashboard
  853.   String html = getHTMLDashboard();
  854.   server.send(200, "text/html", html);
  855. }
  856.  
  857. void handleAPIStatus() {
  858.   // Return JSON status with all current parameters and readings
  859.   StaticJsonDocument<512> doc;
  860.  
  861.   doc["program"] = program;
  862.   doc["SetV"] = SetV;
  863.   doc["ArcV"] = ArcV / 10.0;  // Convert to voltage units
  864.   doc["DT"] = DT / 10.0;      // Convert to seconds
  865.   doc["HyS"] = HyS / 10.0;    // Convert to voltage units
  866.   doc["StV"] = StV;
  867.   doc["outputUp"] = digitalRead(outputUpPin);
  868.   doc["outputDown"] = digitalRead(outputDnPin);
  869.   doc["outputOk"] = digitalRead(outputOkPin);
  870.   doc["arcStatus"] = (ArcV > 500 && ArcV < 2500) ? "OK" : "LOST";
  871.   doc["torchStatus"] = digitalRead(outputUpPin) ? "UP" : (digitalRead(outputDnPin) ? "DOWN" : "STOP");
  872.  
  873.   String response;
  874.   serializeJson(doc, response);
  875.   server.send(200, "application/json", response);
  876. }
  877.  
  878. void handleAPIParameters() {
  879.   // GET: Return current parameters
  880.   StaticJsonDocument<256> doc;
  881.  
  882.   doc["SetV"] = SetV;
  883.   doc["DT"] = DT / 10.0;
  884.   doc["HyS"] = HyS / 10.0;
  885.   doc["StV"] = StV;
  886.   doc["program"] = program;
  887.  
  888.   String response;
  889.   serializeJson(doc, response);
  890.   server.send(200, "application/json", response);
  891. }
  892.  
  893. void handleAPISetParameters() {
  894.   // POST: Set parameters via JSON
  895.   if (!server.hasArg("plain")) {
  896.     server.send(400, "application/json", "{\"error\":\"No body\"}");
  897.     return;
  898.   }
  899.  
  900.   String body = server.arg("plain");
  901.   StaticJsonDocument<256> doc;
  902.   DeserializationError error = deserializeJson(doc, body);
  903.  
  904.   if (error) {
  905.     server.send(400, "application/json", "{\"error\":\"Invalid JSON\"}");
  906.     return;
  907.   }
  908.  
  909.   // Update parameters if provided
  910.   if (doc.containsKey("SetV")) {
  911.     SetV = constrain(doc["SetV"], 50, 250);
  912.     SaveData(SetVa, SetV);
  913.   }
  914.   if (doc.containsKey("DT")) {
  915.     DT = constrain((int)(doc["DT"] * 10), 1, 200);
  916.     SaveData(DTa, DT);
  917.   }
  918.   if (doc.containsKey("HyS")) {
  919.     HyS = constrain((int)(doc["HyS"] * 10), 1, 99);
  920.     SaveData(HySa, HyS);
  921.   }
  922.   if (doc.containsKey("StV")) {
  923.     StV = constrain(doc["StV"], 50, 250);
  924.     SaveData(StVa, StV);
  925.   }
  926.  
  927.   server.send(200, "application/json", "{\"status\":\"OK\"}");
  928. }
  929.  
  930. void handleAPIGetProgram() {
  931.   // Return currently loaded program number
  932.   StaticJsonDocument<64> doc;
  933.   doc["program"] = program;
  934.  
  935.   String response;
  936.   serializeJson(doc, response);
  937.   server.send(200, "application/json", response);
  938. }
  939.  
  940. void handleAPISetProgram() {
  941.   // POST: Load a program (1-3)
  942.   if (!server.hasArg("plain")) {
  943.     server.send(400, "application/json", "{\"error\":\"No body\"}");
  944.     return;
  945.   }
  946.  
  947.   String body = server.arg("plain");
  948.   StaticJsonDocument<64> doc;
  949.   DeserializationError error = deserializeJson(doc, body);
  950.  
  951.   if (error) {
  952.     server.send(400, "application/json", "{\"error\":\"Invalid JSON\"}");
  953.     return;
  954.   }
  955.  
  956.   int prog = doc["program"];
  957.   if (prog >= 1 && prog <= 3) {
  958.     doProgramSet(prog);
  959.     server.send(200, "application/json", "{\"status\":\"OK\"}");
  960.   } else {
  961.     server.send(400, "application/json", "{\"error\":\"Program must be 1-3\"}");
  962.   }
  963. }
  964.  
  965. void handleAPIControl() {
  966.   // POST: Control torch manually (for test mode via web)
  967.   if (!server.hasArg("plain")) {
  968.     server.send(400, "application/json", "{\"error\":\"No body\"}");
  969.     return;
  970.   }
  971.  
  972.   String body = server.arg("plain");
  973.   StaticJsonDocument<128> doc;
  974.   DeserializationError error = deserializeJson(doc, body);
  975.  
  976.   if (error) {
  977.     server.send(400, "application/json", "{\"error\":\"Invalid JSON\"}");
  978.     return;
  979.   }
  980.  
  981.   if (doc.containsKey("command")) {
  982.     String cmd = doc["command"];
  983.    
  984.     if (cmd == "up") {
  985.       digitalWrite(outputUpPin, HIGH);
  986.       digitalWrite(outputDnPin, LOW);
  987.       digitalWrite(outputOkPin, HIGH);
  988.       server.send(200, "application/json", "{\"status\":\"UP\"}");
  989.     } else if (cmd == "down") {
  990.       digitalWrite(outputUpPin, LOW);
  991.       digitalWrite(outputDnPin, HIGH);
  992.       digitalWrite(outputOkPin, HIGH);
  993.       server.send(200, "application/json", "{\"status\":\"DOWN\"}");
  994.     } else if (cmd == "stop") {
  995.       digitalWrite(outputUpPin, LOW);
  996.       digitalWrite(outputDnPin, LOW);
  997.       digitalWrite(outputOkPin, LOW);
  998.       server.send(200, "application/json", "{\"status\":\"STOP\"}");
  999.     } else {
  1000.       server.send(400, "application/json", "{\"error\":\"Unknown command\"}");
  1001.     }
  1002.   } else {
  1003.     server.send(400, "application/json", "{\"error\":\"No command\"}");
  1004.   }
  1005. }
  1006.  
  1007. void handleAPIArcVoltage() {
  1008.   // Real-time arc voltage monitoring
  1009.   StaticJsonDocument<128> doc;
  1010.   doc["arcVoltage"] = ArcV / 10.0;
  1011.   doc["unit"] = "V";
  1012.   doc["status"] = (ArcV > 500 && ArcV < 2500) ? "OK" : "LOST";
  1013.   doc["timestamp"] = millis();
  1014.  
  1015.   String response;
  1016.   serializeJson(doc, response);
  1017.   server.send(200, "application/json", response);
  1018. }
  1019.  
  1020. // ========== HTML DASHBOARD ==========
  1021. String getHTMLDashboard() {
  1022.   String html = R"rawliteral(
  1023. <!DOCTYPE html>
  1024. <html>
  1025. <head>
  1026.  <meta name="viewport" content="width=device-width, initial-scale=1">
  1027.  <title>THC ESP32 Control Panel</title>
  1028.  <style>
  1029.    * { margin: 0; padding: 0; box-sizing: border-box; }
  1030.    body {
  1031.      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  1032.      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  1033.      min-height: 100vh;
  1034.      padding: 20px;
  1035.    }
  1036.    .container {
  1037.      max-width: 1200px;
  1038.      margin: 0 auto;
  1039.      background: white;
  1040.      border-radius: 15px;
  1041.      box-shadow: 0 20px 60px rgba(0,0,0,0.3);
  1042.      padding: 30px;
  1043.    }
  1044.    h1 {
  1045.      color: #333;
  1046.      margin-bottom: 10px;
  1047.      text-align: center;
  1048.    }
  1049.    .subtitle {
  1050.      text-align: center;
  1051.      color: #666;
  1052.      margin-bottom: 30px;
  1053.    }
  1054.    .grid {
  1055.      display: grid;
  1056.      grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  1057.      gap: 20px;
  1058.      margin-bottom: 30px;
  1059.    }
  1060.    .card {
  1061.      background: #f8f9fa;
  1062.      border-left: 5px solid #667eea;
  1063.      padding: 20px;
  1064.      border-radius: 8px;
  1065.      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  1066.    }
  1067.    .card h2 {
  1068.      color: #667eea;
  1069.      font-size: 18px;
  1070.      margin-bottom: 15px;
  1071.    }
  1072.    .status-display {
  1073.      font-size: 32px;
  1074.      font-weight: bold;
  1075.      color: #333;
  1076.      text-align: center;
  1077.      padding: 20px;
  1078.      background: white;
  1079.      border-radius: 8px;
  1080.      margin-bottom: 10px;
  1081.    }
  1082.    .status-ok { color: #28a745; }
  1083.    .status-warning { color: #ffc107; }
  1084.    .status-danger { color: #dc3545; }
  1085.    .label {
  1086.      color: #666;
  1087.      font-size: 14px;
  1088.      margin-bottom: 5px;
  1089.    }
  1090.    .value {
  1091.      color: #333;
  1092.      font-size: 24px;
  1093.      font-weight: bold;
  1094.    }
  1095.    .param-input {
  1096.      margin-bottom: 15px;
  1097.    }
  1098.    label {
  1099.      display: block;
  1100.      color: #333;
  1101.      margin-bottom: 5px;
  1102.      font-weight: 500;
  1103.    }
  1104.    input[type="number"],
  1105.    input[type="range"],
  1106.    select {
  1107.      width: 100%;
  1108.      padding: 10px;
  1109.      border: 2px solid #ddd;
  1110.      border-radius: 5px;
  1111.      font-size: 16px;
  1112.      transition: border-color 0.3s;
  1113.    }
  1114.    input:focus, select:focus {
  1115.      outline: none;
  1116.      border-color: #667eea;
  1117.      box-shadow: 0 0 5px rgba(102, 126, 234, 0.3);
  1118.    }
  1119.    .btn {
  1120.      background: #667eea;
  1121.      color: white;
  1122.      padding: 12px 24px;
  1123.      border: none;
  1124.      border-radius: 5px;
  1125.      font-size: 16px;
  1126.      font-weight: 600;
  1127.      cursor: pointer;
  1128.      transition: all 0.3s;
  1129.      margin-right: 10px;
  1130.      margin-bottom: 10px;
  1131.    }
  1132.    .btn:hover {
  1133.      background: #5568d3;
  1134.      transform: translateY(-2px);
  1135.      box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
  1136.    }
  1137.    .btn-danger {
  1138.      background: #dc3545;
  1139.    }
  1140.    .btn-danger:hover {
  1141.      background: #c82333;
  1142.    }
  1143.    .btn-success {
  1144.      background: #28a745;
  1145.    }
  1146.    .btn-success:hover {
  1147.      background: #218838;
  1148.    }
  1149.    .btn-warning {
  1150.      background: #ffc107;
  1151.      color: #333;
  1152.    }
  1153.    .btn-warning:hover {
  1154.      background: #e0a800;
  1155.    }
  1156.    .torch-status {
  1157.      text-align: center;
  1158.      padding: 20px;
  1159.      background: white;
  1160.      border-radius: 8px;
  1161.      margin: 10px 0;
  1162.    }
  1163.    .torch-indicator {
  1164.      display: inline-block;
  1165.      width: 60px;
  1166.      height: 60px;
  1167.      border-radius: 50%;
  1168.      margin-bottom: 10px;
  1169.      animation: pulse 1s infinite;
  1170.    }
  1171.    .torch-up { background: #28a745; }
  1172.    .torch-down { background: #dc3545; }
  1173.    .torch-stop { background: #ffc107; }
  1174.    @keyframes pulse {
  1175.      0%, 100% { opacity: 1; }
  1176.      50% { opacity: 0.6; }
  1177.    }
  1178.    .graph-container {
  1179.      background: white;
  1180.      padding: 20px;
  1181.      border-radius: 8px;
  1182.      margin-bottom: 20px;
  1183.    }
  1184.    #voltageChart {
  1185.      width: 100%;
  1186.      height: 300px;
  1187.    }
  1188.    .control-buttons {
  1189.      display: flex;
  1190.      gap: 10px;
  1191.      flex-wrap: wrap;
  1192.      margin-top: 15px;
  1193.    }
  1194.    .table {
  1195.      width: 100%;
  1196.      border-collapse: collapse;
  1197.      margin-top: 10px;
  1198.    }
  1199.    .table td {
  1200.      padding: 10px;
  1201.      border-bottom: 1px solid #ddd;
  1202.    }
  1203.    .table td:first-child {
  1204.      font-weight: 600;
  1205.      color: #333;
  1206.      width: 40%;
  1207.    }
  1208.    .table td:last-child {
  1209.      color: #667eea;
  1210.      font-weight: 600;
  1211.      text-align: right;
  1212.    }
  1213.    .loading {
  1214.      display: none;
  1215.      text-align: center;
  1216.      padding: 20px;
  1217.    }
  1218.    .spinner {
  1219.      border: 4px solid #f3f3f3;
  1220.      border-top: 4px solid #667eea;
  1221.      border-radius: 50%;
  1222.      width: 40px;
  1223.      height: 40px;
  1224.      animation: spin 1s linear infinite;
  1225.      margin: 0 auto;
  1226.    }
  1227.    @keyframes spin {
  1228.      0% { transform: rotate(0deg); }
  1229.      100% { transform: rotate(360deg); }
  1230.    }
  1231.  </style>
  1232. </head>
  1233. <body>
  1234.  <div class="container">
  1235.    <h1>🔥 THC ESP32 Control Panel</h1>
  1236.    <p class="subtitle">Torch Height Control System - Real-time Monitoring & Control</p>
  1237.    
  1238.    <div class="grid">
  1239.      <!-- Real-time Arc Voltage Monitoring -->
  1240.      <div class="card">
  1241.        <h2>Arc Voltage Monitor</h2>
  1242.        <div class="status-display status-ok" id="arcVoltageDisplay">-- V</div>
  1243.        <div class="label">Current Arc Voltage</div>
  1244.        <div class="value" id="arcVoltageValue">0.0 V</div>
  1245.        <div class="label" style="margin-top: 10px;">Status:</div>
  1246.        <div class="value" id="arcStatus">LOST</div>
  1247.      </div>
  1248.      
  1249.      <!-- Set Voltage Control -->
  1250.      <div class="card">
  1251.        <h2>Set Voltage</h2>
  1252.        <div class="param-input">
  1253.          <label for="setVoltage">Target Voltage (V):</label>
  1254.          <input type="number" id="setVoltage" min="50" max="250" value="100" step="1">
  1255.          <div style="margin-top: 5px; text-align: center; font-size: 20px; color: #667eea; font-weight: bold;" id="setVoltageDisplay">100 V</div>
  1256.         </div>
  1257.       </div>
  1258.      
  1259.       <!-- Program Selection -->
  1260.       <div class="card">
  1261.         <h2>Program Selection</h2>
  1262.         <div class="param-input">
  1263.           <label for="programSelect">Load Program:</label>
  1264.           <select id="programSelect">
  1265.             <option value="1">Program 1</option>
  1266.             <option value="2">Program 2</option>
  1267.             <option value="3">Program 3</option>
  1268.           </select>
  1269.         </div>
  1270.         <button class="btn btn-success" onclick="loadProgram()">Load Program</button>
  1271.       </div>
  1272.      
  1273.       <!-- Torch Status Display -->
  1274.       <div class="card">
  1275.         <h2>Torch Status</h2>
  1276.         <div class="torch-status">
  1277.           <div class="torch-indicator" id="torchIndicator" style="background: #ffc107;"></div>
  1278.           <div style="font-size: 20px; font-weight: bold; color: #333;" id="torchStatusText">STOP</div>
  1279.         </div>
  1280.       </div>
  1281.      
  1282.       <!-- Manual Control -->
  1283.       <div class="card">
  1284.         <h2>Manual Control</h2>
  1285.         <div class="control-buttons">
  1286.           <button class="btn btn-success" onclick="controlTorch('up')">⬆️ Move UP</button>
  1287.           <button class="btn btn-danger" onclick="controlTorch('down')">⬇️ Move DOWN</button>
  1288.           <button class="btn btn-warning" onclick="controlTorch('stop')">⏹️ STOP</button>
  1289.         </div>
  1290.       </div>
  1291.      
  1292.       <!-- Advanced Parameters -->
  1293.       <div class="card" style="grid-column: 1 / -1;">
  1294.         <h2>Advanced Parameters</h2>
  1295.         <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px;">
  1296.           <div class="param-input">
  1297.             <label for="delayTime">Delay Time (s):</label>
  1298.             <input type="number" id="delayTime" min="0.1" max="20" value="0.5" step="0.1">
  1299.             <div style="margin-top: 5px; font-size: 14px; color: #666;" id="delayTimeDisplay">0.5 s</div>
  1300.           </div>
  1301.           <div class="param-input">
  1302.             <label for="hysteresis">Hysteresis (V):</label>
  1303.             <input type="number" id="hysteresis" min="0.1" max="9.9" value="8.0" step="0.1">
  1304.             <div style="margin-top: 5px; font-size: 14px; color: #666;" id="hysteresisDisplay">8.0 V</div>
  1305.           </div>
  1306.           <div class="param-input">
  1307.             <label for="startVoltage">Start Voltage (V):</label>
  1308.             <input type="number" id="startVoltage" min="50" max="250" value="100" step="1">
  1309.             <div style="margin-top: 5px; font-size: 14px; color: #666;" id="startVoltageDisplay">100 V</div>
  1310.           </div>
  1311.         </div>
  1312.         <button class="btn btn-success" onclick="saveParameters()">💾 Save Parameters</button>
  1313.       </div>
  1314.     </div>
  1315.    
  1316.     <!-- Status Information Table -->
  1317.     <div class="card">
  1318.       <h2>System Status</h2>
  1319.       <table class="table" id="statusTable">
  1320.         <tr>
  1321.           <td>Program</td>
  1322.           <td id="statusProgram">--</td>
  1323.         </tr>
  1324.         <tr>
  1325.           <td>Arc Voltage</td>
  1326.           <td id="statusArcV">0.0 V</td>
  1327.         </tr>
  1328.         <tr>
  1329.           <td>Set Voltage</td>
  1330.           <td id="statusSetV">100 V</td>
  1331.         </tr>
  1332.         <tr>
  1333.           <td>Torch Position</td>
  1334.           <td id="statusTorchPos">STOP</td>
  1335.         </tr>
  1336.         <tr>
  1337.           <td>Arc Status</td>
  1338.           <td id="statusArcStatus">LOST</td>
  1339.         </tr>
  1340.       </table>
  1341.     </div>
  1342.   </div>
  1343.  
  1344.   <script>
  1345.     // Auto-refresh status every 500ms
  1346.     const refreshInterval = setInterval(updateStatus, 500);
  1347.    
  1348.     // Update all displays from API
  1349.     async function updateStatus() {
  1350.       try {
  1351.         const response = await fetch('/api/status');
  1352.         const data = await response.json();
  1353.        
  1354.         // Update displays
  1355.         document.getElementById('arcVoltageDisplay').textContent = data.ArcV.toFixed(1) + ' V';
  1356.         document.getElementById('arcVoltageValue').textContent = data.ArcV.toFixed(1) + ' V';
  1357.         document.getElementById('arcStatus').textContent = data.arcStatus;
  1358.         document.getElementById('statusArcV').textContent = data.ArcV.toFixed(1) + ' V';
  1359.         document.getElementById('statusSetV').textContent = data.SetV + ' V';
  1360.         document.getElementById('statusProgram').textContent = data.program;
  1361.         document.getElementById('statusArcStatus').textContent = data.arcStatus;
  1362.         document.getElementById('torchStatusText').textContent = data.torchStatus;
  1363.         document.getElementById('statusTorchPos').textContent = data.torchStatus;
  1364.        
  1365.         // Update torch indicator color
  1366.         const indicator = document.getElementById('torchIndicator');
  1367.         if (data.torchStatus === 'UP') {
  1368.           indicator.className = 'torch-indicator torch-up';
  1369.         } else if (data.torchStatus === 'DOWN') {
  1370.           indicator.className = 'torch-indicator torch-down';
  1371.         } else {
  1372.           indicator.className = 'torch-indicator torch-stop';
  1373.         }
  1374.        
  1375.         // Update arc voltage display color
  1376.         const arcDisplay = document.getElementById('arcVoltageDisplay');
  1377.         if (data.arcStatus === 'OK') {
  1378.           arcDisplay.className = 'status-display status-ok';
  1379.         } else {
  1380.           arcDisplay.className = 'status-display status-danger';
  1381.         }
  1382.       } catch (error) {
  1383.         console.error('Error updating status:', error);
  1384.       }
  1385.     }
  1386.    
  1387.     // Save parameters to EEPROM via API
  1388.     async function saveParameters() {
  1389.       const params = {
  1390.         SetV: parseInt(document.getElementById('setVoltage').value),
  1391.         DT: parseFloat(document.getElementById('delayTime').value),
  1392.         HyS: parseFloat(document.getElementById('hysteresis').value),
  1393.         StV: parseInt(document.getElementById('startVoltage').value)
  1394.       };
  1395.      
  1396.       try {
  1397.         const response = await fetch('/api/parameters', {
  1398.           method: 'POST',
  1399.           headers: { 'Content-Type': 'application/json' },
  1400.           body: JSON.stringify(params)
  1401.         });
  1402.         const result = await response.json();
  1403.         alert('Parameters saved!');
  1404.       } catch (error) {
  1405.         alert('Error saving parameters: ' + error);
  1406.       }
  1407.     }
  1408.    
  1409.     // Load program from API
  1410.     async function loadProgram() {
  1411.       const prog = parseInt(document.getElementById('programSelect').value);
  1412.      
  1413.       try {
  1414.         const response = await fetch('/api/program', {
  1415.           method: 'POST',
  1416.           headers: { 'Content-Type': 'application/json' },
  1417.           body: JSON.stringify({ program: prog })
  1418.         });
  1419.         const result = await response.json();
  1420.         alert('Program ' + prog + ' loaded!');
  1421.         updateStatus();
  1422.       } catch (error) {
  1423.         alert('Error loading program: ' + error);
  1424.       }
  1425.     }
  1426.    
  1427.     // Control torch manually
  1428.     async function controlTorch(command) {
  1429.       try {
  1430.         const response = await fetch('/api/control', {
  1431.           method: 'POST',
  1432.           headers: { 'Content-Type': 'application/json' },
  1433.           body: JSON.stringify({ command: command })
  1434.         });
  1435.         const result = await response.json();
  1436.         updateStatus();
  1437.       } catch (error) {
  1438.         alert('Error controlling torch: ' + error);
  1439.       }
  1440.     }
  1441.    
  1442.     // Update display values when inputs change
  1443.     document.getElementById('setVoltage').addEventListener('input', function() {
  1444.       document.getElementById('setVoltageDisplay').textContent = this.value + ' V';
  1445.     });
  1446.    
  1447.     document.getElementById('delayTime').addEventListener('input', function() {
  1448.       document.getElementById('delayTimeDisplay').textContent = this.value + ' s';
  1449.     });
  1450.    
  1451.     document.getElementById('hysteresis').addEventListener('input', function() {
  1452.       document.getElementById('hysteresisDisplay').textContent = this.value + ' V';
  1453.     });
  1454.    
  1455.     document.getElementById('startVoltage').addEventListener('input', function() {
  1456.       document.getElementById('startVoltageDisplay').textContent = this.value + ' V';
  1457.     });
  1458.    
  1459.     // Initial status update
  1460.     updateStatus();
  1461.   </script>
  1462. </body>
  1463. </html>
  1464.   )rawliteral";
  1465.  
  1466.  return html;
  1467. }
  1468.  
  1469. // ========== MAIN SETUP FUNCTION ==========
  1470. void setup() {
  1471.  // Initialize Serial for debugging
  1472.  Serial.begin(115200);
  1473.  delay(1000);
  1474.  
  1475.  Serial.println("\n\n=== THC ESP32 System Starting ===");
  1476.  
  1477.  // Initialize EEPROM
  1478.  EEPROM.begin(512);
  1479.  
  1480.  // Initialize THC system
  1481.  Setup_THC();
  1482.  Serial.println("THC initialized");
  1483.  
  1484.  // Initialize Timer
  1485.  Setup_Timer();
  1486.  Serial.println("Timer initialized (10ms interval)");
  1487.  
  1488.  // Initialize LCD
  1489.  Setup_LCD();
  1490.  Serial.println("LCD initialized");
  1491.  
  1492.  // Initialize Encoder
  1493.  pinMode(pinCLK, INPUT_PULLUP);
  1494.  pinMode(pinDT, INPUT_PULLUP);
  1495.  pinMode(pinSW, INPUT_PULLUP);
  1496.  attachInterrupt(digitalPinToInterrupt(pinCLK), isrEncoder, CHANGE);
  1497.  Serial.println("Encoder initialized");
  1498.  
  1499.  // Configure ADC for arc voltage
  1500.  analogSetAttenuation(ADC_11db);  // Full range: 0-3.3V
  1501.  Serial.println("ADC configured");
  1502.  
  1503.  // Load program from EEPROM
  1504.  ReadProg();
  1505.  if (program < 1 || program > 3) {
  1506.    program = 1;
  1507.  }
  1508.  doProgramSet(program);
  1509.  Serial.print("Program ");
  1510.  Serial.print(program);
  1511.  Serial.println(" loaded");
  1512.  
  1513.  // Initialize Web Server
  1514.  Setup_WebServer();
  1515.  Serial.println("Web server initialized");
  1516.  
  1517.  Serial.println("=== System Ready ===\n");
  1518. }
  1519.  
  1520. // ========== MAIN LOOP FUNCTION ==========
  1521. void loop() {
  1522.  // Handle incoming HTTP requests
  1523.  server.handleClient();
  1524.  
  1525.  // Read arc voltage periodically
  1526.  readArcVoltage();
  1527.  
  1528.  // Execute THC control algorithm
  1529.  doTHC();
  1530.  
  1531.  // Update LCD display
  1532.  doLCD();
  1533.  
  1534.  // Handle encoder button press
  1535.  handleEncoderButton();
  1536.  
  1537.  // Small delay to prevent watchdog timeout
  1538.  delay(5);
  1539. }
  1540.  
  1541. /* END CODE */
  1542.  
Advertisement
Add Comment
Please, Sign In to add comment