pleasedontcode

# Plasma Height Controller rev_05

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