pleasedontcode

# Automated Torchwork rev_06

Jan 23rd, 2026
22
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 39.55 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: # Automated Torchwork
  13.     - Source Code compiled for: ESP32 DevKit V1
  14.     - Source Code created on: 2026-01-23 16:17:56
  15.  
  16. ********* Pleasedontcode.com **********/
  17.  
  18. /****** SYSTEM REQUIREMENTS *****/
  19. /****** SYSTEM REQUIREMENT 1 *****/
  20.     /* Integrasikan web server HTTP pada ESP32 dengan */
  21.     /* JSON API untuk memantau tegangan busur 0-250V */
  22.     /* secara real-time, menampilkan status obor */
  23.     /* (UP/DOWN) pada LCD I2C, dan mengontrol program 3 */
  24.     /* parameter melalui encoder KY-040 lokal atau */
  25.     /* endpoint web. */
  26. /****** END SYSTEM REQUIREMENTS *****/
  27.  
  28.  
  29.  
  30. /* START CODE */
  31.  
  32. #include <WiFi.h>
  33. #include <WebServer.h>
  34. #include <ArduinoJson.h>
  35. #include <EEPROM.h>
  36. #include <LiquidCrystal_I2C.h>
  37.  
  38. // ===== WiFi Configuration =====
  39. const char* ssid = "ANLOG";
  40. const char* password = "serversatu1";
  41. WebServer server(80);
  42.  
  43. // ===== LCD Configuration =====
  44. LiquidCrystal_I2C lcd(0x27, 16, 2);
  45.  
  46. // ===== Hardware Pin Configuration =====
  47. const int pinCLK = 12;        // Encoder CLK pin
  48. const int pinDT = 14;         // Encoder DT pin
  49. const int pinSW = 27;         // Encoder Switch pin
  50. const int adcPin = 35;        // ADC pin for arc voltage (0-250V)
  51. const int outputUpPin = 25;   // Output: Torch UP control
  52. const int outputDnPin = 26;   // Output: Torch DOWN control
  53. const int outputOkPin = 33;   // Output: Arc OK signal
  54.  
  55. // ===== System Timing Variables =====
  56. esp_timer_handle_t timer_handle = NULL;
  57. volatile bool Do = false;
  58. unsigned long LCDtime = 0;
  59. unsigned long defaultLCDtime = 500;  // 5 seconds auto-return (500 * 10ms)
  60.  
  61. // ===== Encoder Variables =====
  62. volatile int encoderCount = 0;
  63. volatile int encoderVal = 0;
  64. int oldValue = 0;
  65. int lastClkState = 0;
  66. unsigned long lastButtonPress = 0;
  67.  
  68. // ===== LCD Display State Variables =====
  69. byte menu = 0;
  70. byte pos = 0;
  71. byte show = 0;
  72.  
  73. // ===== Arc Voltage Monitoring =====
  74. unsigned long ArcV = 0;        // Arc voltage in 0.1V units (0-2500 = 0-250V)
  75. unsigned long voltageSum = 0;
  76. int sampleCount = 0;
  77.  
  78. // ===== Program and Parameter Management =====
  79. int program = 1;              // Current program (1-3)
  80. int Param[12] = {0};          // Parameter array for 3 programs (4 params each)
  81. int SetVa = 0, DTa = 1, HySa = 2, StVa = 3;  // Current param addresses
  82. int SetV = 100, DT = 5, HyS = 80, StV = 100; // Current parameter values
  83. int SetV_old = 0;             // For change detection
  84. const int ParamItem = 4;      // 4 parameters per program
  85.  
  86. // ===== THC Control Variables =====
  87. unsigned int delayTime = 0;
  88. unsigned int SetVx10 = 0;
  89.  
  90. // ===== Custom LCD Characters =====
  91. byte armsUpDn[8] = {
  92.   B00000,
  93.   B00100,
  94.   B01110,
  95.   B00100,
  96.   B00000,
  97.   B01110,
  98.   B00000,
  99.   B00000
  100. };
  101.  
  102. byte customUp[8] = {
  103.   B00100,
  104.   B01110,
  105.   B10101,
  106.   B00100,
  107.   B00100,
  108.   B00100,
  109.   B00100,
  110.   B00000
  111. };
  112.  
  113. byte customDown[8] = {
  114.   B00100,
  115.   B00100,
  116.   B00100,
  117.   B00100,
  118.   B10101,
  119.   B01110,
  120.   B00100,
  121.   B00000
  122. };
  123.  
  124. // ===== Forward Declarations =====
  125. void Setup_WiFi();
  126. void Setup_LCD();
  127. void Setup_Encoder();
  128. void Setup_ADC();
  129. void Setup_THC();
  130. void Setup_Timer();
  131. void doLCD();
  132. void doTHC();
  133. void readArcVoltage();
  134. void SaveData(int add, int value);
  135. void ReadProg();
  136. void ReadDataProg_1();
  137. void ReadDataProg_2();
  138. void ReadDataProg_3();
  139. void Default();
  140. void doProgramSet(int prg);
  141. void doLCDDefault();
  142. void doLCDMenu();
  143. void doLCDProgramSellect();
  144. void doLCDMenuSetup();
  145. void doLCDTest();
  146. void doTestUp();
  147. void doTestDown();
  148. void doLCDDelayTime();
  149. void doLCDHysreresis();
  150. void doLCDStartVoltage();
  151. void doLCDLoadDefault();
  152. void IRAM_ATTR isrEncoder();
  153. void IRAM_ATTR isrButton();
  154.  
  155. // ===== Web Server Handlers =====
  156. void handleRoot();
  157. void handleGetStatus();
  158. void handleSetParameter();
  159. void handleControl();
  160. void handleNotFound();
  161.  
  162. void setup() {
  163.   Serial.begin(115200);
  164.   delay(1000);
  165.  
  166.   Serial.println("\n\nStarting THC Rotary Control System...");
  167.  
  168.   // Initialize EEPROM for persistent storage
  169.   EEPROM.begin(64);
  170.  
  171.   // Initialize all subsystems
  172.   Setup_LCD();
  173.   Setup_Encoder();
  174.   Setup_ADC();
  175.   Setup_THC();
  176.   Setup_Timer();
  177.   Setup_WiFi();
  178.  
  179.   // Initialize web server routes
  180.   server.on("/", HTTP_GET, handleRoot);
  181.   server.on("/api/status", HTTP_GET, handleGetStatus);
  182.   server.on("/api/param", HTTP_POST, handleSetParameter);
  183.   server.on("/api/control", HTTP_POST, handleControl);
  184.   server.onNotFound(handleNotFound);
  185.  
  186.   server.begin();
  187.   Serial.println("HTTP Server started");
  188.  
  189.   // Load program data from EEPROM
  190.   ReadProg();
  191.   if (program < 1 || program > 3) program = 1;
  192.   doProgramSet(program);
  193.  
  194.   Serial.println("System initialization complete");
  195. }
  196.  
  197. void loop() {
  198.   // Handle WiFi and HTTP requests
  199.   server.handleClient();
  200.  
  201.   // Process LCD display updates
  202.   doLCD();
  203.  
  204.   // Process THC (Torch Height Control) logic
  205.   doTHC();
  206.  
  207.   // Handle button press (encoder switch)
  208.   if (digitalRead(pinSW) == LOW) {
  209.     if (millis() - lastButtonPress > 200) {
  210.       Serial.println("Button pressed");
  211.       if (menu == 0) {
  212.         menu = 1;
  213.         encoderVal = 0;
  214.       } else {
  215.         // Navigate menus
  216.         if (menu == 1) {
  217.           // Main menu selection
  218.           if (pos == 0) menu = 0;          // Exit
  219.           else if (pos == 1) menu = 13;    // Program
  220.           else if (pos == 2) menu = 11;    // Setup
  221.           else if (pos == 3) menu = 12;    // Test
  222.         } else if (menu == 13) {
  223.           // Program selection
  224.           if (pos == 0) menu = 1;          // Exit
  225.           else if (pos == 1) menu = 121;   // Program 1
  226.           else if (pos == 2) menu = 122;   // Program 2
  227.           else if (pos == 3) menu = 123;   // Program 3
  228.         } else if (menu == 11) {
  229.           // Setup menu selection
  230.           if (pos == 0) menu = 1;          // Exit
  231.           else if (pos == 1) menu = 111;   // Delay Time
  232.           else if (pos == 2) menu = 112;   // Hysteresis
  233.           else if (pos == 3) menu = 113;   // Start Voltage
  234.           else if (pos == 4) menu = 114;   // Load Default
  235.         } else if (menu == 12) {
  236.           // Test mode selection
  237.           if (pos == 0) menu = 1;          // Exit
  238.           else if (pos == 1) menu = 115;   // Torch Up
  239.           else if (pos == 2) menu = 116;   // Torch Down
  240.         } else if (menu >= 111 && menu <= 116) {
  241.           menu = 11;  // Return to setup/test menu
  242.         }
  243.       }
  244.       lastButtonPress = millis();
  245.     }
  246.   }
  247. }
  248.  
  249. // ===== Timer Callback (runs every 10ms) =====
  250. void onTimerCallback(void* arg) {
  251.   Do = true;
  252. }
  253.  
  254. // ===== Setup Functions =====
  255.  
  256. void Setup_WiFi() {
  257.   Serial.print("Connecting to WiFi: ");
  258.   Serial.println(ssid);
  259.  
  260.   WiFi.mode(WIFI_STA);
  261.   WiFi.begin(ssid, password);
  262.  
  263.   int attempts = 0;
  264.   while (WiFi.status() != WL_CONNECTED && attempts < 40) {
  265.     delay(500);
  266.     Serial.print(".");
  267.     attempts++;
  268.   }
  269.  
  270.   Serial.println();
  271.   if (WiFi.status() == WL_CONNECTED) {
  272.     Serial.println("WiFi connected!");
  273.     Serial.print("IP address: ");
  274.     Serial.println(WiFi.localIP());
  275.   } else {
  276.     Serial.println("WiFi connection failed!");
  277.   }
  278. }
  279.  
  280. void Setup_LCD() {
  281.   lcd.init();
  282.   lcd.backlight();
  283.  
  284.   // Create custom characters
  285.   lcd.createChar(0, armsUpDn);
  286.   lcd.createChar(1, customUp);
  287.   lcd.createChar(2, customDown);
  288.  
  289.   // Display splash screen
  290.   lcd.setCursor(1, 0);
  291.   lcd.print("MEHMET IBRAHIM");
  292.   lcd.setCursor(3, 1);
  293.   lcd.print("Plasma THC");
  294.   delay(1500);
  295.   lcd.clear();
  296. }
  297.  
  298. void Setup_Encoder() {
  299.   pinMode(pinCLK, INPUT_PULLUP);
  300.   pinMode(pinDT, INPUT_PULLUP);
  301.   pinMode(pinSW, INPUT_PULLUP);
  302.  
  303.   lastClkState = digitalRead(pinCLK);
  304.   attachInterrupt(digitalPinToInterrupt(pinCLK), isrEncoder, CHANGE);
  305.  
  306.   Serial.println("Encoder initialized");
  307. }
  308.  
  309. void Setup_ADC() {
  310.   analogReadResolution(12);  // 12-bit resolution
  311.  
  312.   // Configure ADC calibration for more accurate readings
  313.   analogSetPinAttenuation(adcPin, ADC_11db);  // Full range 0-3.3V
  314.  
  315.   Serial.println("ADC initialized");
  316. }
  317.  
  318. void Setup_THC() {
  319.   pinMode(outputUpPin, OUTPUT);
  320.   pinMode(outputDnPin, OUTPUT);
  321.   pinMode(outputOkPin, OUTPUT);
  322.  
  323.   // Set initial state: all outputs LOW
  324.   digitalWrite(outputUpPin, LOW);
  325.   digitalWrite(outputDnPin, LOW);
  326.   digitalWrite(outputOkPin, LOW);
  327.  
  328.   Serial.println("THC control outputs initialized");
  329. }
  330.  
  331. void Setup_Timer() {
  332.   esp_timer_create_args_t timer_args = {
  333.     .callback = &onTimerCallback,
  334.     .name = "thc_periodic_timer"
  335.   };
  336.  
  337.   ESP_ERROR_CHECK(esp_timer_create(&timer_args, &timer_handle));
  338.   ESP_ERROR_CHECK(esp_timer_start_periodic(timer_handle, 10000));  // 10ms period
  339.  
  340.   Serial.println("Timer initialized");
  341. }
  342.  
  343. // ===== Encoder Interrupt Service Routine =====
  344. void IRAM_ATTR isrEncoder() {
  345.   int currentClkState = digitalRead(pinCLK);
  346.   if (currentClkState != lastClkState && currentClkState == LOW) {
  347.     if (digitalRead(pinDT) != currentClkState) {
  348.       encoderVal++;
  349.     } else {
  350.       encoderVal--;
  351.     }
  352.   }
  353.   lastClkState = currentClkState;
  354. }
  355.  
  356. // ===== ADC Reading Function =====
  357. void readArcVoltage() {
  358.   // Read ADC value (12-bit: 0-4095)
  359.   int rawValue = analogRead(adcPin);
  360.  
  361.   // Convert to voltage (3.3V reference, divided by voltage divider)
  362.   // Voltage divider: 250V -> 3.3V requires 75:1 ratio
  363.   // ADC reading * 3.3V / 4095 * divider_ratio = arc voltage
  364.   // For 250V max: divider = 250V / 3.3V approx 75.76
  365.  
  366.   // Convert to 0-250V range and store in 0.1V units
  367.   // ADC 0-4095 maps to 0-250V = 0-2500 in 0.1V units
  368.   ArcV = (rawValue * 2500UL) / 4095UL;
  369. }
  370.  
  371. // ===== LCD Display Functions =====
  372.  
  373. void doLCD() {
  374.   if (show >= 2) {
  375.     show = 0;
  376.    
  377.     switch (menu) {
  378.       case 0:
  379.         doLCDDefault();
  380.         break;
  381.       case 1:
  382.         doLCDMenu();
  383.         break;
  384.       case 11:
  385.         doLCDMenuSetup();
  386.         break;
  387.       case 111:
  388.         doLCDDelayTime();
  389.         break;
  390.       case 112:
  391.         doLCDHysreresis();
  392.         break;
  393.       case 113:
  394.         doLCDStartVoltage();
  395.         break;
  396.       case 114:
  397.         doLCDLoadDefault();
  398.         break;
  399.       case 12:
  400.         doLCDTest();
  401.         break;
  402.       case 115:
  403.         doTestUp();
  404.         break;
  405.       case 116:
  406.         doTestDown();
  407.         break;
  408.       case 13:
  409.         doLCDProgramSellect();
  410.         break;
  411.       case 121:
  412.         doProgramSet(1);
  413.         break;
  414.       case 122:
  415.         doProgramSet(2);
  416.         break;
  417.       case 123:
  418.         doProgramSet(3);
  419.         break;
  420.       default:
  421.         doLCDDefault();
  422.     }
  423.   }
  424. }
  425.  
  426. void doLCDDefault() {
  427.   // Constrain encoder value to valid voltage range
  428.   if (encoderVal < 0) encoderVal = 0;
  429.   else if (encoderVal > 250) encoderVal = 250;
  430.  
  431.   SetV = encoderVal;
  432.  
  433.   // Save to EEPROM if value changed
  434.   if (SetV != oldValue) {
  435.     SaveData(SetVa, SetV);
  436.     oldValue = SetV;
  437.   }
  438.  
  439.   // Display: [P] [UP/space] [SetV] on line 0
  440.   lcd.setCursor(0, 0);
  441.   lcd.print("P ");
  442.  
  443.   if (digitalRead(outputUpPin) == HIGH) {
  444.     lcd.write(1);  // UP arrow
  445.   } else {
  446.     lcd.print(" ");
  447.   }
  448.  
  449.   lcd.print(" ");
  450.   lcd.setCursor(4, 0);
  451.   lcd.print("Set.V: ");
  452.   lcd.print(SetV);
  453.   lcd.print("   ");
  454.  
  455.   // Display: [prog] [DOWN/space] [ArcV] on line 1
  456.   lcd.setCursor(0, 1);
  457.   lcd.print(program);
  458.   lcd.print(" ");
  459.  
  460.   if (digitalRead(outputDnPin) == HIGH) {
  461.     lcd.write(2);  // DOWN arrow
  462.   } else {
  463.     lcd.print(" ");
  464.   }
  465.  
  466.   lcd.print(" ");
  467.   lcd.setCursor(4, 1);
  468.   lcd.print("Arc.V: ");
  469.   lcd.print(ArcV / 10);
  470.   lcd.print("   ");
  471. }
  472.  
  473. void doLCDMenu() {
  474.   // Menu: Exit, Program, Setup, Test
  475.   if (encoderVal < 0) encoderVal = 3;
  476.   pos = encoderVal % 4;
  477.  
  478.   switch (pos) {
  479.     case 0:
  480.       lcd.setCursor(0, 0);
  481.       lcd.print("> Exit          ");
  482.       lcd.setCursor(0, 1);
  483.       lcd.print("  Program       ");
  484.       break;
  485.     case 1:
  486.       lcd.setCursor(0, 0);
  487.       lcd.print("> Program       ");
  488.       lcd.setCursor(0, 1);
  489.       lcd.print("  Setup         ");
  490.       break;
  491.     case 2:
  492.       lcd.setCursor(0, 0);
  493.       lcd.print("> Setup         ");
  494.       lcd.setCursor(0, 1);
  495.       lcd.print("  Test          ");
  496.       break;
  497.     case 3:
  498.       lcd.setCursor(0, 0);
  499.       lcd.print("> Test          ");
  500.       lcd.setCursor(0, 1);
  501.       lcd.print("  Exit          ");
  502.       break;
  503.   }
  504. }
  505.  
  506. void doLCDProgramSellect() {
  507.   // Program selection: Exit, Program 1, Program 2, Program 3
  508.   if (encoderVal < 0) encoderVal = 3;
  509.   pos = abs(encoderVal % 4);
  510.  
  511.   switch (pos) {
  512.     case 0:
  513.       lcd.setCursor(0, 0);
  514.       lcd.print(">> Exit         ");
  515.       lcd.setCursor(0, 1);
  516.       lcd.print("   Load Prog: 1 ");
  517.       break;
  518.     case 1:
  519.       lcd.setCursor(0, 0);
  520.       lcd.print(">> Load Prog: 1 ");
  521.       lcd.setCursor(0, 1);
  522.       lcd.print("   Load Prog: 2 ");
  523.       break;
  524.     case 2:
  525.       lcd.setCursor(0, 0);
  526.       lcd.print(">> Load Prog: 2 ");
  527.       lcd.setCursor(0, 1);
  528.       lcd.print("   Load Prog: 3 ");
  529.       break;
  530.     case 3:
  531.       lcd.setCursor(0, 0);
  532.       lcd.print(">> Load Prog: 3 ");
  533.       lcd.setCursor(0, 1);
  534.       lcd.print("   Exit         ");
  535.       break;
  536.   }
  537. }
  538.  
  539. void doLCDMenuSetup() {
  540.   // Setup menu: Exit, Delay Time, Hysteresis, Start Voltage, Load Default
  541.   if (encoderVal < 0) encoderVal = 4;
  542.   pos = abs(encoderVal % 5);
  543.  
  544.   switch (pos) {
  545.     case 0:
  546.       lcd.setCursor(0, 0);
  547.       lcd.print(">> Exit         ");
  548.       lcd.setCursor(0, 1);
  549.       lcd.print("   Delay Time   ");
  550.       break;
  551.     case 1:
  552.       lcd.setCursor(0, 0);
  553.       lcd.print(">> Delay Time   ");
  554.       lcd.setCursor(0, 1);
  555.       lcd.print("   Hysteresis   ");
  556.       break;
  557.     case 2:
  558.       lcd.setCursor(0, 0);
  559.       lcd.print(">> Hysteresis   ");
  560.       lcd.setCursor(0, 1);
  561.       lcd.print("   Start Voltage");
  562.       break;
  563.     case 3:
  564.       lcd.setCursor(0, 0);
  565.       lcd.print(">> Start Voltage");
  566.       lcd.setCursor(0, 1);
  567.       lcd.print("   Load Default ");
  568.       break;
  569.     case 4:
  570.       lcd.setCursor(0, 0);
  571.       lcd.print(">> Load Default ");
  572.       lcd.setCursor(0, 1);
  573.       lcd.print("   Exit         ");
  574.       break;
  575.   }
  576. }
  577.  
  578. void doLCDTest() {
  579.   // Test mode: Exit, Torch Up, Torch Down
  580.   if (encoderVal < 0) encoderVal = 2;
  581.   pos = abs(encoderVal % 3);
  582.  
  583.   switch (pos) {
  584.     case 0:
  585.       lcd.setCursor(0, 0);
  586.       lcd.print("Test > Exit     ");
  587.       lcd.setCursor(0, 1);
  588.       lcd.print("       Torch Up ");
  589.       digitalWrite(outputDnPin, LOW);
  590.       digitalWrite(outputUpPin, LOW);
  591.       digitalWrite(outputOkPin, LOW);
  592.       break;
  593.     case 1:
  594.       lcd.setCursor(0, 0);
  595.       lcd.print("Test > Torch Up ");
  596.       lcd.setCursor(0, 1);
  597.       lcd.print("       Torch Dn ");
  598.       if (digitalRead(outputOkPin) == LOW) LCDtime = 0;
  599.       if (LCDtime >= 200) {  // 2 seconds (200 * 10ms)
  600.         digitalWrite(outputDnPin, LOW);
  601.         digitalWrite(outputUpPin, LOW);
  602.         digitalWrite(outputOkPin, LOW);
  603.       }
  604.       break;
  605.     case 2:
  606.       lcd.setCursor(0, 0);
  607.       lcd.print("Test > Torch Dn ");
  608.       lcd.setCursor(0, 1);
  609.       lcd.print("       Exit     ");
  610.       if (digitalRead(outputOkPin) == LOW) LCDtime = 0;
  611.       if (LCDtime >= 200) {
  612.         digitalWrite(outputDnPin, LOW);
  613.         digitalWrite(outputUpPin, LOW);
  614.         digitalWrite(outputOkPin, LOW);
  615.       }
  616.       break;
  617.   }
  618. }
  619.  
  620. void doTestUp() {
  621.   // Execute torch up command
  622.   digitalWrite(outputDnPin, LOW);
  623.   digitalWrite(outputUpPin, HIGH);
  624.   digitalWrite(outputOkPin, HIGH);
  625.   LCDtime = 0;
  626.   menu = 12;
  627.   encoderVal = 1;
  628. }
  629.  
  630. void doTestDown() {
  631.   // Execute torch down command
  632.   digitalWrite(outputDnPin, HIGH);
  633.   digitalWrite(outputUpPin, LOW);
  634.   digitalWrite(outputOkPin, HIGH);
  635.   LCDtime = 0;
  636.   menu = 12;
  637.   encoderVal = 2;
  638. }
  639.  
  640. void doLCDDelayTime() {
  641.   // Delay Time adjustment: 1-200 units (0.1s to 20.0s)
  642.   if (encoderVal < 1) encoderVal = 1;
  643.   else if (encoderVal > 200) encoderVal = 200;
  644.  
  645.   DT = encoderVal;
  646.  
  647.   if (DT != oldValue) {
  648.     SaveData(DTa, DT);
  649.     oldValue = DT;
  650.     LCDtime = 0;
  651.   }
  652.  
  653.   double x = DT / 10.00;
  654.   lcd.setCursor(0, 0);
  655.   lcd.print("Set > Delay Time");
  656.   lcd.setCursor(0, 1);
  657.   lcd.print("     : ");
  658.   lcd.print(x, 1);
  659.   lcd.print(" s       ");
  660. }
  661.  
  662. void doLCDHysreresis() {
  663.   // Hysteresis adjustment: 1-99 units (plusminus 0.1V to plusminus 9.9V)
  664.   if (encoderVal < 1) encoderVal = 1;
  665.   else if (encoderVal > 99) encoderVal = 99;
  666.  
  667.   HyS = encoderVal;
  668.  
  669.   if (HyS != oldValue) {
  670.     SaveData(HySa, HyS);
  671.     oldValue = HyS;
  672.     LCDtime = 0;
  673.   }
  674.  
  675.   double x = HyS / 10.00;
  676.   lcd.setCursor(0, 0);
  677.   lcd.print("Set > Hysteresis");
  678.   lcd.setCursor(0, 1);
  679.   lcd.print("     :");
  680.   lcd.write(0);
  681.   lcd.print(x, 1);
  682.   lcd.print(" V       ");
  683. }
  684.  
  685. void doLCDStartVoltage() {
  686.   // Start Voltage adjustment: 50-250V
  687.   if (encoderVal < 50) encoderVal = 50;
  688.   else if (encoderVal > 250) encoderVal = 250;
  689.  
  690.   StV = encoderVal;
  691.  
  692.   if (StV != oldValue) {
  693.     SaveData(StVa, StV);
  694.     oldValue = StV;
  695.     LCDtime = 0;
  696.   }
  697.  
  698.   lcd.setCursor(0, 0);
  699.   lcd.print("Set > Start Volt");
  700.   lcd.setCursor(0, 1);
  701.   lcd.print("     : ");
  702.   lcd.print(StV);
  703.   lcd.print(" V       ");
  704. }
  705.  
  706. void doLCDLoadDefault() {
  707.   // Load default parameters
  708.   Default();
  709.  
  710.   for (byte i = 0; i < 100; i++) {
  711.     lcd.setCursor(0, 0);
  712.     lcd.print("     Default    ");
  713.     lcd.setCursor(0, 1);
  714.     lcd.print("Load   ");
  715.     lcd.print(i);
  716.     lcd.print(" %      ");
  717.     delay(5);
  718.   }
  719.  
  720.   lcd.setCursor(0, 0);
  721.   lcd.print("Default:  DONE  ");
  722.   lcd.setCursor(0, 1);
  723.   lcd.print("Please Restart  ");
  724.  
  725.   exit(0);
  726. }
  727.  
  728. void doProgramSet(int prg) {
  729.   // Set program and load its parameters
  730.   if (prg == 1) {
  731.     SetVa = 0;
  732.     DTa = 1;
  733.     HySa = 2;
  734.     StVa = 3;
  735.     ReadDataProg_1();
  736.   } else if (prg == 2) {
  737.     SetVa = 4;
  738.     DTa = 5;
  739.     HySa = 6;
  740.     StVa = 7;
  741.     ReadDataProg_2();
  742.   } else {
  743.     SetVa = 8;
  744.     DTa = 9;
  745.     HySa = 10;
  746.     StVa = 11;
  747.     ReadDataProg_3();
  748.   }
  749.  
  750.   SaveData(12, prg);
  751.   program = prg;
  752.  
  753.   SetV = Param[0];
  754.   DT = Param[1];
  755.   HyS = Param[2];
  756.   StV = Param[3];
  757.  
  758.   encoderVal = SetV;
  759.   menu = 0;
  760. }
  761.  
  762. // ===== THC Logic =====
  763.  
  764. void doTHC() {
  765.   if (Do) {
  766.     Do = false;
  767.     LCDtime++;
  768.     show++;
  769.    
  770.     // Read arc voltage from ADC
  771.     readArcVoltage();
  772.    
  773.     // Auto-return to default menu after timeout
  774.     if (LCDtime > defaultLCDtime) {
  775.       menu = 0;
  776.       pos = 0;
  777.       LCDtime = 0;
  778.       encoderVal = SetV;
  779.     }
  780.    
  781.     // Arc voltage validation: 50V < ArcV < 250V (500 < value < 2500 in 0.1V units)
  782.     if ((500 < ArcV) && (ArcV < 2500)) {
  783.       // Wait for arc to stabilize above start voltage
  784.       if (ArcV > StV * 10) {
  785.         delayTime++;
  786.       }
  787.      
  788.       // After stabilization delay, enable arc control
  789.       if (delayTime >= DT * 10) {
  790.         SetVx10 = SetV * 10;
  791.         delayTime = DT * 10;
  792.        
  793.         digitalWrite(outputOkPin, HIGH);  // Arc OK signal
  794.        
  795.         // Torch height control hysteresis logic
  796.         if (ArcV >= SetVx10 + HyS) {
  797.           // Arc voltage too high, move torch down
  798.           digitalWrite(outputUpPin, LOW);
  799.           digitalWrite(outputDnPin, HIGH);
  800.         } else if (ArcV <= SetVx10 - HyS) {
  801.           // Arc voltage too low, move torch up
  802.           digitalWrite(outputDnPin, LOW);
  803.           digitalWrite(outputUpPin, HIGH);
  804.         } else {
  805.           // Arc voltage within target range, hold position
  806.           digitalWrite(outputUpPin, LOW);
  807.           digitalWrite(outputDnPin, LOW);
  808.         }
  809.       }
  810.     } else if (menu != 12) {
  811.       // Arc lost or invalid, disable all outputs
  812.       delayTime = 0;
  813.       digitalWrite(outputUpPin, LOW);
  814.       digitalWrite(outputOkPin, LOW);
  815.       digitalWrite(outputDnPin, LOW);
  816.     }
  817.   }
  818. }
  819.  
  820. // ===== EEPROM Functions =====
  821.  
  822. void Default() {
  823.   // Initialize EEPROM with default values for all 3 programs
  824.  
  825.   // Program 1: SetV=100V, DT=0.5s, HyS=8.0V, StV=100V
  826.   EEPROM.write(0, 100);   // SetV
  827.   EEPROM.write(1, 5);     // DT (0.5s = 5 * 0.1s)
  828.   EEPROM.write(2, 80);    // HyS (8.0V = 80 * 0.1V)
  829.   EEPROM.write(3, 100);   // StV
  830.  
  831.   // Program 2: SetV=120V, DT=0.5s, HyS=8.0V, StV=110V
  832.   EEPROM.write(4, 120);   // SetV
  833.   EEPROM.write(5, 5);     // DT
  834.   EEPROM.write(6, 80);    // HyS
  835.   EEPROM.write(7, 110);   // StV
  836.  
  837.   // Program 3: SetV=140V, DT=0.5s, HyS=8.0V, StV=120V
  838.   EEPROM.write(8, 140);   // SetV
  839.   EEPROM.write(9, 5);     // DT
  840.   EEPROM.write(10, 80);   // HyS
  841.   EEPROM.write(11, 120);  // StV
  842.  
  843.   // Default program selection
  844.   EEPROM.write(12, 1);
  845.  
  846.   EEPROM.commit();
  847. }
  848.  
  849. void ReadProg() {
  850.   // Read current program selection from EEPROM
  851.   int prog = EEPROM.read(12);
  852.   if (prog >= 1 && prog <= 3) {
  853.     program = prog;
  854.   } else {
  855.     program = 1;
  856.   }
  857. }
  858.  
  859. void ReadDataProg_1() {
  860.   // Read Program 1 parameters (addresses 0-3)
  861.   for (int j = 0; j < ParamItem; j++) {
  862.     Param[j] = EEPROM.read(j);
  863.   }
  864. }
  865.  
  866. void ReadDataProg_2() {
  867.   // Read Program 2 parameters (addresses 4-7)
  868.   for (int j = 0; j < ParamItem; j++) {
  869.     Param[j] = EEPROM.read(j + 4);
  870.   }
  871. }
  872.  
  873. void ReadDataProg_3() {
  874.   // Read Program 3 parameters (addresses 8-11)
  875.   for (int j = 0; j < ParamItem; j++) {
  876.     Param[j] = EEPROM.read(j + 8);
  877.   }
  878. }
  879.  
  880. void SaveData(int add, int value) {
  881.   // Save a single value to EEPROM and commit
  882.   EEPROM.write(add, value);
  883.   EEPROM.commit();
  884. }
  885.  
  886. // ===== Web Server Handlers =====
  887.  
  888. void handleRoot() {
  889.   // Serve HTML control interface with proper character encoding
  890.   String html = "<!DOCTYPE html>\n<html>\n<head>\n";
  891.   html += "  <meta charset=\"UTF-8\">\n";
  892.   html += "  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n";
  893.   html += "  <title>THC Control System</title>\n";
  894.   html += "  <style>\n";
  895.   html += "    body {\n";
  896.   html += "      font-family: Arial, sans-serif;\n";
  897.   html += "      max-width: 800px;\n";
  898.   html += "      margin: 50px auto;\n";
  899.   html += "      padding: 20px;\n";
  900.   html += "      background-color: #f5f5f5;\n";
  901.   html += "    }\n";
  902.   html += "    h1 {\n";
  903.   html += "      color: #333;\n";
  904.   html += "      text-align: center;\n";
  905.   html += "    }\n";
  906.   html += "    .container {\n";
  907.   html += "      background: white;\n";
  908.   html += "      padding: 20px;\n";
  909.   html += "      border-radius: 8px;\n";
  910.   html += "      box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n";
  911.   html += "      margin-bottom: 20px;\n";
  912.   html += "    }\n";
  913.   html += "    .status-box {\n";
  914.   html += "      background-color: #f9f9f9;\n";
  915.   html += "      padding: 15px;\n";
  916.   html += "      border-left: 4px solid #4CAF50;\n";
  917.   html += "      margin-bottom: 15px;\n";
  918.   html += "    }\n";
  919.   html += "    .status-item {\n";
  920.   html += "      margin: 8px 0;\n";
  921.   html += "      font-size: 16px;\n";
  922.   html += "    }\n";
  923.   html += "    .status-value {\n";
  924.   html += "      font-weight: bold;\n";
  925.   html += "      color: #4CAF50;\n";
  926.   html += "    }\n";
  927.   html += "    .control-section {\n";
  928.   html += "      margin: 20px 0;\n";
  929.   html += "    }\n";
  930.   html += "    .control-section h3 {\n";
  931.   html += "      color: #333;\n";
  932.   html += "      border-bottom: 2px solid #4CAF50;\n";
  933.   html += "      padding-bottom: 10px;\n";
  934.   html += "    }\n";
  935.   html += "    label {\n";
  936.   html += "      display: inline-block;\n";
  937.   html += "      width: 150px;\n";
  938.   html += "      font-weight: bold;\n";
  939.   html += "      color: #555;\n";
  940.   html += "    }\n";
  941.   html += "    input[type=\"number\"] {\n";
  942.   html += "      width: 100px;\n";
  943.   html += "      padding: 8px;\n";
  944.   html += "      margin: 5px;\n";
  945.   html += "      border: 1px solid #ddd;\n";
  946.   html += "      border-radius: 4px;\n";
  947.   html += "    }\n";
  948.   html += "    button {\n";
  949.   html += "      background-color: #4CAF50;\n";
  950.   html += "      color: white;\n";
  951.   html += "      padding: 10px 20px;\n";
  952.   html += "      margin: 5px;\n";
  953.   html += "      border: none;\n";
  954.   html += "      border-radius: 4px;\n";
  955.   html += "      cursor: pointer;\n";
  956.   html += "      font-size: 16px;\n";
  957.   html += "      font-weight: bold;\n";
  958.   html += "    }\n";
  959.   html += "    button:hover {\n";
  960.   html += "      background-color: #45a049;\n";
  961.   html += "    }\n";
  962.   html += "    button.danger {\n";
  963.   html += "      background-color: #f44336;\n";
  964.   html += "    }\n";
  965.   html += "    button.danger:hover {\n";
  966.   html += "      background-color: #da190b;\n";
  967.   html += "    }\n";
  968.   html += "    .select-program {\n";
  969.   html += "      margin: 10px 0;\n";
  970.   html += "    }\n";
  971.   html += "    .response {\n";
  972.   html += "      background-color: #e8f5e9;\n";
  973.   html += "      border: 1px solid #4CAF50;\n";
  974.   html += "      padding: 10px;\n";
  975.   html += "      border-radius: 4px;\n";
  976.   html += "      margin-top: 10px;\n";
  977.   html += "      display: none;\n";
  978.   html += "    }\n";
  979.   html += "    .error {\n";
  980.   html += "      background-color: #ffebee;\n";
  981.   html += "      border: 1px solid #f44336;\n";
  982.   html += "      color: #c62828;\n";
  983.   html += "    }\n";
  984.   html += "  </style>\n";
  985.   html += "</head>\n<body>\n";
  986.   html += "  <h1>THC (Torch Height Control) System</h1>\n";
  987.   html += "  \n";
  988.   html += "  <div class=\"container\">\n";
  989.   html += "    <h2>Current Status</h2>\n";
  990.   html += "    <div class=\"status-box\">\n";
  991.   html += "      <div class=\"status-item\">Arc Voltage: <span class=\"status-value\" id=\"arcVoltage\">0</span> V</div>\n";
  992.   html += "      <div class=\"status-item\">Set Voltage: <span class=\"status-value\" id=\"setVoltage\">0</span> V</div>\n";
  993.   html += "      <div class=\"status-item\">Program: <span class=\"status-value\" id=\"program\">1</span></div>\n";
  994.   html += "      <div class=\"status-item\">Torch Status: <span class=\"status-value\" id=\"torchStatus\">IDLE</span></div>\n";
  995.   html += "      <div class=\"status-item\">Delay Time: <span class=\"status-value\" id=\"delayTime\">0</span> s</div>\n";
  996.   html += "      <div class=\"status-item\">Hysteresis: <span class=\"status-value\" id=\"hysteresis\">0</span> V</div>\n";
  997.   html += "      <div class=\"status-item\">Start Voltage: <span class=\"status-value\" id=\"startVoltage\">0</span> V</div>\n";
  998.   html += "    </div>\n";
  999.   html += "  </div>\n";
  1000.   html += "  \n";
  1001.   html += "  <div class=\"container\">\n";
  1002.   html += "    <h2>Program Selection</h2>\n";
  1003.   html += "    <div class=\"select-program\">\n";
  1004.   html += "      <label>Select Program:</label>\n";
  1005.   html += "      <select id=\"programSelect\">\n";
  1006.   html += "        <option value=\"1\">Program 1</option>\n";
  1007.   html += "        <option value=\"2\">Program 2</option>\n";
  1008.   html += "        <option value=\"3\">Program 3</option>\n";
  1009.   html += "      </select>\n";
  1010.   html += "      <button onclick=\"loadProgram()\">Load Program</button>\n";
  1011.   html += "    </div>\n";
  1012.   html += "  </div>\n";
  1013.   html += "  \n";
  1014.   html += "  <div class=\"container\">\n";
  1015.   html += "    <h2>Parameter Control</h2>\n";
  1016.   html += "    <div class=\"control-section\">\n";
  1017.   html += "      <h3>Set Voltage (0-250V)</h3>\n";
  1018.   html += "      <label>Value:</label>\n";
  1019.   html += "      <input type=\"number\" id=\"setVoltageSetting\" min=\"0\" max=\"250\" value=\"100\">\n";
  1020.   html += "      <button onclick=\"setParameter('SetV')\">Set</button>\n";
  1021.   html += "    </div>\n";
  1022.   html += "    \n";
  1023.   html += "    <div class=\"control-section\">\n";
  1024.   html += "      <h3>Delay Time (0.1-20.0s)</h3>\n";
  1025.   html += "      <label>Value:</label>\n";
  1026.   html += "      <input type=\"number\" id=\"delayTimeSetting\" min=\"1\" max=\"200\" value=\"5\" step=\"1\">\n";
  1027.   html += "      <span> (x 0.1s)</span>\n";
  1028.   html += "      <button onclick=\"setParameter('DT')\">Set</button>\n";
  1029.   html += "    </div>\n";
  1030.   html += "    \n";
  1031.   html += "    <div class=\"control-section\">\n";
  1032.   html += "      <h3>Hysteresis (Range 0.1-9.9V)</h3>\n";
  1033.   html += "      <label>Value:</label>\n";
  1034.   html += "      <input type=\"number\" id=\"hysteresisSetting\" min=\"1\" max=\"99\" value=\"80\" step=\"1\">\n";
  1035.   html += "      <span> (x 0.1V)</span>\n";
  1036.   html += "      <button onclick=\"setParameter('HyS')\">Set</button>\n";
  1037.   html += "    </div>\n";
  1038.   html += "    \n";
  1039.   html += "    <div class=\"control-section\">\n";
  1040.   html += "      <h3>Start Voltage (50-250V)</h3>\n";
  1041.   html += "      <label>Value:</label>\n";
  1042.   html += "      <input type=\"number\" id=\"startVoltageSetting\" min=\"50\" max=\"250\" value=\"100\">\n";
  1043.   html += "      <button onclick=\"setParameter('StV')\">Set</button>\n";
  1044.   html += "    </div>\n";
  1045.   html += "  </div>\n";
  1046.   html += "  \n";
  1047.   html += "  <div class=\"container\">\n";
  1048.   html += "    <h2>Torch Control</h2>\n";
  1049.   html += "    <div class=\"control-section\">\n";
  1050.   html += "      <button onclick=\"torchUp()\">Torch UP</button>\n";
  1051.   html += "      <button onclick=\"torchDown()\" class=\"danger\">Torch DOWN</button>\n";
  1052.   html += "      <button onclick=\"torchStop()\" class=\"danger\">STOP</button>\n";
  1053.   html += "    </div>\n";
  1054.   html += "  </div>\n";
  1055.   html += "  \n";
  1056.   html += "  <div id=\"response\" class=\"response\"></div>\n";
  1057.   html += "  \n";
  1058.   html += "  <script>\n";
  1059.   html += "    const API_BASE = '/api';\n";
  1060.   html += "    \n";
  1061.   html += "    function updateStatus() {\n";
  1062.   html += "      fetch(API_BASE + '/status')\n";
  1063.   html += "        .then(response => response.json())\n";
  1064.   html += "        .then(data => {\n";
  1065.   html += "          document.getElementById('arcVoltage').textContent = (data.arc_voltage / 10).toFixed(1);\n";
  1066.   html += "          document.getElementById('setVoltage').textContent = data.set_voltage;\n";
  1067.   html += "          document.getElementById('program').textContent = data.program;\n";
  1068.   html += "          document.getElementById('torchStatus').textContent = data.torch_status;\n";
  1069.   html += "          document.getElementById('delayTime').textContent = (data.delay_time / 10).toFixed(1);\n";
  1070.   html += "          document.getElementById('hysteresis').textContent = (data.hysteresis / 10).toFixed(1);\n";
  1071.   html += "          document.getElementById('startVoltage').textContent = data.start_voltage;\n";
  1072.   html += "          document.getElementById('programSelect').value = data.program;\n";
  1073.   html += "        })\n";
  1074.   html += "        .catch(error => showResponse('Error fetching status: ' + error, true));\n";
  1075.   html += "    }\n";
  1076.   html += "    \n";
  1077.   html += "    function setParameter(param) {\n";
  1078.   html += "      let value = 0;\n";
  1079.   html += "      if (param === 'SetV') {\n";
  1080.   html += "        value = document.getElementById('setVoltageSetting').value;\n";
  1081.   html += "      } else if (param === 'DT') {\n";
  1082.   html += "        value = document.getElementById('delayTimeSetting').value;\n";
  1083.   html += "      } else if (param === 'HyS') {\n";
  1084.   html += "        value = document.getElementById('hysteresisSetting').value;\n";
  1085.   html += "      } else if (param === 'StV') {\n";
  1086.   html += "        value = document.getElementById('startVoltageSetting').value;\n";
  1087.   html += "      }\n";
  1088.   html += "      \n";
  1089.   html += "      fetch(API_BASE + '/param', {\n";
  1090.   html += "        method: 'POST',\n";
  1091.   html += "        headers: {\n";
  1092.   html += "          'Content-Type': 'application/json',\n";
  1093.   html += "        },\n";
  1094.   html += "        body: JSON.stringify({\n";
  1095.   html += "          param: param,\n";
  1096.   html += "          value: parseInt(value),\n";
  1097.   html += "          program: parseInt(document.getElementById('programSelect').value)\n";
  1098.   html += "        })\n";
  1099.   html += "      })\n";
  1100.   html += "      .then(response => response.json())\n";
  1101.   html += "      .then(data => {\n";
  1102.   html += "        if (data.success) {\n";
  1103.   html += "          showResponse(param + ' set to ' + value);\n";
  1104.   html += "          updateStatus();\n";
  1105.   html += "        } else {\n";
  1106.   html += "          showResponse('Error: ' + data.message, true);\n";
  1107.   html += "        }\n";
  1108.   html += "      })\n";
  1109.   html += "      .catch(error => showResponse('Error: ' + error, true));\n";
  1110.   html += "    }\n";
  1111.   html += "    \n";
  1112.   html += "    function loadProgram() {\n";
  1113.   html += "      const program = document.getElementById('programSelect').value;\n";
  1114.   html += "      fetch(API_BASE + '/param', {\n";
  1115.   html += "        method: 'POST',\n";
  1116.   html += "        headers: {\n";
  1117.   html += "          'Content-Type': 'application/json',\n";
  1118.   html += "        },\n";
  1119.   html += "        body: JSON.stringify({\n";
  1120.   html += "          param: 'PROGRAM',\n";
  1121.   html += "          value: parseInt(program)\n";
  1122.   html += "        })\n";
  1123.   html += "      })\n";
  1124.   html += "      .then(response => response.json())\n";
  1125.   html += "      .then(data => {\n";
  1126.   html += "        if (data.success) {\n";
  1127.   html += "          showResponse('Program ' + program + ' loaded');\n";
  1128.   html += "          updateStatus();\n";
  1129.   html += "        } else {\n";
  1130.   html += "          showResponse('Error: ' + data.message, true);\n";
  1131.   html += "        }\n";
  1132.   html += "      })\n";
  1133.   html += "      .catch(error => showResponse('Error: ' + error, true));\n";
  1134.   html += "    }\n";
  1135.   html += "    \n";
  1136.   html += "    function torchUp() {\n";
  1137.   html += "      fetch(API_BASE + '/control', {\n";
  1138.   html += "        method: 'POST',\n";
  1139.   html += "        headers: {\n";
  1140.   html += "          'Content-Type': 'application/json',\n";
  1141.   html += "        },\n";
  1142.   html += "        body: JSON.stringify({\n";
  1143.   html += "          action: 'UP'\n";
  1144.   html += "        })\n";
  1145.   html += "      })\n";
  1146.   html += "      .then(response => response.json())\n";
  1147.   html += "      .then(data => {\n";
  1148.   html += "        showResponse('Torch moving UP');\n";
  1149.   html += "        updateStatus();\n";
  1150.   html += "      })\n";
  1151.   html += "      .catch(error => showResponse('Error: ' + error, true));\n";
  1152.   html += "    }\n";
  1153.   html += "    \n";
  1154.   html += "    function torchDown() {\n";
  1155.   html += "      fetch(API_BASE + '/control', {\n";
  1156.   html += "        method: 'POST',\n";
  1157.   html += "        headers: {\n";
  1158.   html += "          'Content-Type': 'application/json',\n";
  1159.   html += "        },\n";
  1160.   html += "        body: JSON.stringify({\n";
  1161.   html += "          action: 'DOWN'\n";
  1162.   html += "        })\n";
  1163.   html += "      })\n";
  1164.   html += "      .then(response => response.json())\n";
  1165.   html += "      .then(data => {\n";
  1166.   html += "        showResponse('Torch moving DOWN');\n";
  1167.   html += "        updateStatus();\n";
  1168.   html += "      })\n";
  1169.   html += "      .catch(error => showResponse('Error: ' + error, true));\n";
  1170.   html += "    }\n";
  1171.   html += "    \n";
  1172.   html += "    function torchStop() {\n";
  1173.   html += "      fetch(API_BASE + '/control', {\n";
  1174.   html += "        method: 'POST',\n";
  1175.   html += "        headers: {\n";
  1176.   html += "          'Content-Type': 'application/json',\n";
  1177.   html += "        },\n";
  1178.   html += "        body: JSON.stringify({\n";
  1179.   html += "          action: 'STOP'\n";
  1180.   html += "        })\n";
  1181.   html += "      })\n";
  1182.   html += "      .then(response => response.json())\n";
  1183.   html += "      .then(data => {\n";
  1184.   html += "        showResponse('Torch STOPPED');\n";
  1185.   html += "        updateStatus();\n";
  1186.   html += "      })\n";
  1187.   html += "      .catch(error => showResponse('Error: ' + error, true));\n";
  1188.   html += "    }\n";
  1189.   html += "    \n";
  1190.   html += "    function showResponse(message, isError = false) {\n";
  1191.   html += "      const response = document.getElementById('response');\n";
  1192.   html += "      response.textContent = message;\n";
  1193.   html += "      response.style.display = 'block';\n";
  1194.   html += "      if (isError) {\n";
  1195.   html += "        response.classList.add('error');\n";
  1196.   html += "      } else {\n";
  1197.   html += "        response.classList.remove('error');\n";
  1198.   html += "      }\n";
  1199.   html += "    }\n";
  1200.   html += "    \n";
  1201.   html += "    // Update status every 500ms\n";
  1202.   html += "    updateStatus();\n";
  1203.   html += "    setInterval(updateStatus, 500);\n";
  1204.   html += "  </script>\n";
  1205.   html += "</body>\n";
  1206.   html += "</html>\n";
  1207.  
  1208.   server.send(200, "text/html", html);
  1209. }
  1210.  
  1211. void handleGetStatus() {
  1212.   // Return current system status as JSON
  1213.   DynamicJsonDocument doc(512);
  1214.  
  1215.   doc["arc_voltage"] = (int)ArcV;         // in 0.1V units
  1216.   doc["set_voltage"] = SetV;              // in V
  1217.   doc["program"] = program;
  1218.   doc["delay_time"] = DT;                 // in 0.1s units
  1219.   doc["hysteresis"] = HyS;                // in 0.1V units
  1220.   doc["start_voltage"] = StV;             // in V
  1221.  
  1222.   // Determine torch status
  1223.   if (digitalRead(outputOkPin) == HIGH) {
  1224.     if (digitalRead(outputUpPin) == HIGH) {
  1225.       doc["torch_status"] = "UP";
  1226.     } else if (digitalRead(outputDnPin) == HIGH) {
  1227.       doc["torch_status"] = "DOWN";
  1228.     } else {
  1229.       doc["torch_status"] = "HOLD";
  1230.     }
  1231.   } else {
  1232.     doc["torch_status"] = "IDLE";
  1233.   }
  1234.  
  1235.   String json;
  1236.   serializeJson(doc, json);
  1237.   server.send(200, "application/json", json);
  1238. }
  1239.  
  1240. void handleSetParameter() {
  1241.   // Parse JSON request to set parameters
  1242.   if (!server.hasArg("plain")) {
  1243.     server.send(400, "application/json", "{\"success\": false, \"message\": \"No data\"}");
  1244.     return;
  1245.   }
  1246.  
  1247.   String body = server.arg("plain");
  1248.   DynamicJsonDocument doc(256);
  1249.   DeserializationError error = deserializeJson(doc, body);
  1250.  
  1251.   if (error) {
  1252.     server.send(400, "application/json", "{\"success\": false, \"message\": \"Invalid JSON\"}");
  1253.     return;
  1254.   }
  1255.  
  1256.   String param = doc["param"];
  1257.   int value = doc["value"];
  1258.   int prog = doc["program"] | program;  // Default to current program
  1259.  
  1260.   DynamicJsonDocument response(256);
  1261.  
  1262.   if (param == "SetV") {
  1263.     if (value >= 0 && value <= 250) {
  1264.       SetV = value;
  1265.       encoderVal = value;
  1266.       SaveData(SetVa, value);
  1267.       Param[0] = value;
  1268.       response["success"] = true;
  1269.     } else {
  1270.       response["success"] = false;
  1271.       response["message"] = "SetV must be 0-250";
  1272.     }
  1273.   } else if (param == "DT") {
  1274.     if (value >= 1 && value <= 200) {
  1275.       DT = value;
  1276.       encoderVal = value;
  1277.       SaveData(DTa, value);
  1278.       Param[1] = value;
  1279.       response["success"] = true;
  1280.     } else {
  1281.       response["success"] = false;
  1282.       response["message"] = "DT must be 1-200 (0.1-20.0s)";
  1283.     }
  1284.   } else if (param == "HyS") {
  1285.     if (value >= 1 && value <= 99) {
  1286.       HyS = value;
  1287.       encoderVal = value;
  1288.       SaveData(HySa, value);
  1289.       Param[2] = value;
  1290.       response["success"] = true;
  1291.     } else {
  1292.       response["success"] = false;
  1293.       response["message"] = "HyS must be 1-99 (Range 0.1-9.9V)";
  1294.     }
  1295.   } else if (param == "StV") {
  1296.     if (value >= 50 && value <= 250) {
  1297.       StV = value;
  1298.       encoderVal = value;
  1299.       SaveData(StVa, value);
  1300.       Param[3] = value;
  1301.       response["success"] = true;
  1302.     } else {
  1303.       response["success"] = false;
  1304.       response["message"] = "StV must be 50-250V";
  1305.     }
  1306.   } else if (param == "PROGRAM") {
  1307.     if (value >= 1 && value <= 3) {
  1308.       doProgramSet(value);
  1309.       response["success"] = true;
  1310.     } else {
  1311.       response["success"] = false;
  1312.       response["message"] = "Program must be 1-3";
  1313.     }
  1314.   } else {
  1315.     response["success"] = false;
  1316.     response["message"] = "Unknown parameter";
  1317.   }
  1318.  
  1319.   String json;
  1320.   serializeJson(response, json);
  1321.   server.send(200, "application/json", json);
  1322. }
  1323.  
  1324. void handleControl() {
  1325.   // Handle torch control commands
  1326.   if (!server.hasArg("plain")) {
  1327.     server.send(400, "application/json", "{\"success\": false, \"message\": \"No data\"}");
  1328.     return;
  1329.   }
  1330.  
  1331.   String body = server.arg("plain");
  1332.   DynamicJsonDocument doc(256);
  1333.   DeserializationError error = deserializeJson(doc, body);
  1334.  
  1335.   if (error) {
  1336.     server.send(400, "application/json", "{\"success\": false, \"message\": \"Invalid JSON\"}");
  1337.     return;
  1338.   }
  1339.  
  1340.   String action = doc["action"];
  1341.   DynamicJsonDocument response(256);
  1342.  
  1343.   if (action == "UP") {
  1344.     digitalWrite(outputDnPin, LOW);
  1345.     digitalWrite(outputUpPin, HIGH);
  1346.     digitalWrite(outputOkPin, HIGH);
  1347.     response["success"] = true;
  1348.     response["message"] = "Torch moving UP";
  1349.   } else if (action == "DOWN") {
  1350.     digitalWrite(outputDnPin, HIGH);
  1351.     digitalWrite(outputUpPin, LOW);
  1352.     digitalWrite(outputOkPin, HIGH);
  1353.     response["success"] = true;
  1354.     response["message"] = "Torch moving DOWN";
  1355.   } else if (action == "STOP") {
  1356.     digitalWrite(outputUpPin, LOW);
  1357.     digitalWrite(outputDnPin, LOW);
  1358.     digitalWrite(outputOkPin, LOW);
  1359.     response["success"] = true;
  1360.     response["message"] = "Torch STOPPED";
  1361.   } else {
  1362.     response["success"] = false;
  1363.     response["message"] = "Unknown action";
  1364.   }
  1365.  
  1366.   String json;
  1367.   serializeJson(response, json);
  1368.   server.send(200, "application/json", json);
  1369. }
  1370.  
  1371. void handleNotFound() {
  1372.   // Handle 404 errors
  1373.   DynamicJsonDocument doc(256);
  1374.   doc["error"] = "Endpoint not found";
  1375.   doc["path"] = server.uri();
  1376.  
  1377.   String json;
  1378.   serializeJson(doc, json);
  1379.   server.send(404, "application/json", json);
  1380. }
  1381.  
  1382. /* END CODE */
  1383.  
Advertisement
Add Comment
Please, Sign In to add comment