esp32 firmware for a toaster reflow oven WIP!!!!!

index.html 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Breadflow Web Control</title>
  6. <style>
  7. * {
  8. box-sizing: content-box;
  9. }
  10. h1 {
  11. text-align: center;
  12. }
  13. #ctab {
  14. width: 1400px;
  15. margin: 0 auto;
  16. border: 1px solid #ccc;
  17. border-collapse: collapse;
  18. }
  19. #td-side {
  20. border-left: 1px solid #ccc;
  21. width: 340px;
  22. padding: 15px;
  23. vertical-align: top;
  24. padding-top: 22px;
  25. }
  26. #td-img {
  27. vertical-align: top;
  28. }
  29. </style>
  30. </head>
  31. <body>
  32. <h1>Breadflow {version}</h1>
  33. <table id="ctab">
  34. <tr>
  35. <td id="td-img">
  36. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 660 430">
  37. <style>
  38. .ticks, .frame {
  39. stroke-width: 1px;
  40. fill: none;
  41. stroke: black;
  42. }
  43. .ylabels text {
  44. font-size: 10px;
  45. text-anchor: start;
  46. font-family: Droid Sans, sans-serif;
  47. vertical-align: middle;
  48. }
  49. .grid {
  50. stroke-dasharray: 2;
  51. stroke: #dbdbdb;
  52. }
  53. .series {
  54. stroke-width: 2px;
  55. fill: none;
  56. }
  57. </style>
  58. <g transform="translate(10,15)">
  59. <path d="M100,0 v400m100,-400 v400m100,-400 v400m100,-400 v400m100,-400 v400m100,-400 v400"
  60. class="grid" transform="translate(0,0)" id="grid-v" />
  61. <path d="M0,100 h600m-600,100 h600m-600,100 h600m-600,100"
  62. class="grid" stroke-dashoffset="0" id="grid-h" />
  63. <path d="M600,0 h10m-10,100 h10m-10,100 h10m-10,100 h10m-10,100 h10" class="ticks" />
  64. <path d="M600,10
  65. h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,20
  66. h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,20
  67. h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,20
  68. h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5m-5,10h5" class="ticks" />
  69. <g class="series">
  70. <path d="{ser-set}" stroke="blue" id="ser-set" /><!--M0,400L600,0-->
  71. <path d="{ser-act}" stroke="red" id="ser-act" /><!--M0,0L300,100L600,400-->
  72. </g>
  73. <path d="M0,0h600v400h-600Z" class="frame" />
  74. <g class="ylabels" transform="translate(630,3)">
  75. <text x="-15" y="0">400 °C</text>
  76. <text x="-15" y="100">300 °C</text>
  77. <text x="-15" y="200">200 °C</text>
  78. <text x="-15" y="300">100 °C</text>
  79. <text x="-15" y="400">0 °C</text>
  80. </g>
  81. </g>
  82. </svg>
  83. </td>
  84. <td id="td-side">
  85. t<sub>sens</sub> = <span id="temp">{temp}</span>°C<br>
  86. <form action="/set" method="POST">
  87. <h3>Oven Control</h3>
  88. <table>
  89. <tr>
  90. <th>Heater:</th>
  91. <td><select name="fire">
  92. <option value="0" {fire_dis_ck}>Disable</option>
  93. <option value="1" {fire_en_ck}>Enable</option>
  94. </select></td>
  95. </tr>
  96. <tr>
  97. <th>t<sub>set</sub> =</th>
  98. <td><input type="number" step="1" name="tset" value="{tset}"></td>
  99. </tr>
  100. <tr><td></td><td><input type="submit" value="Set"></td></tr>
  101. </table>
  102. </form>
  103. <form action="/set" method="POST">
  104. <h3>PID tuning</h3>
  105. <table>
  106. <tr><th>Kp = </th><td><input type="number" step="any" name="kp" value="{kp}"></td></tr>
  107. <tr><th>Ki = </th><td><input type="number" step="any" name="ki" value="{ki}"></td></tr>
  108. <tr><th>Kd = </th><td><input type="number" step="any" name="kd" value="{kd}"></td></tr>
  109. <tr><td></td><td><input type="submit" value="Set"></td></tr>
  110. </table>
  111. </form>
  112. </td>
  113. </tr>
  114. </table>
  115. <script>
  116. let Qi = function (x) { return document.getElementById(x) };
  117. const REFR_TIME = 1000;
  118. function update(data) {
  119. if (data) {
  120. let rows = data.split('\x1e');
  121. rows.forEach(function (v) {
  122. let [k, va] = v.split('\x1f');
  123. switch (k) {
  124. case 'ser-set':
  125. Qi('ser-set').setAttribute('d', va);
  126. break;
  127. case 'ser-act':
  128. Qi('ser-act').setAttribute('d', va);
  129. break;
  130. case 'timeshift':
  131. Qi('grid-v').setAttribute('transform', 'translate(-'+(va*5)+',0)');
  132. Qi('grid-h').setAttribute('stroke-dashoffset', -va * 5);
  133. break;
  134. case 'temp':
  135. Qi('temp').innerHTML = va;
  136. break;
  137. // form fields are not live updated.
  138. }
  139. });
  140. } else {
  141. let xhr=new XMLHttpRequest();
  142. xhr.onreadystatechange = function () {
  143. if (xhr.readyState===4){
  144. if (xhr.status===200) {
  145. update(xhr.responseText);
  146. }
  147. setTimeout(update, REFR_TIME);
  148. }
  149. };
  150. xhr.onerror = function () {
  151. setTimeout(update, REFR_TIME);
  152. };
  153. xhr.open('GET', '/data');
  154. xhr.send();
  155. }
  156. }
  157. setTimeout(update, REFR_TIME);
  158. </script>