index.html 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>ESPWoL</title>
  8. <style>
  9. body{
  10. font-family: Arial, sans-serif;
  11. color: #262626;
  12. }
  13. .box {
  14. display: flex;
  15. align-items: center;
  16. justify-content: center;
  17. }
  18. .wallpaper{
  19. position: absolute;
  20. width: 100%;
  21. height: 100%;
  22. left: 0;
  23. top: 0;
  24. background-color: #ffffff;
  25. }
  26. .main{
  27. width: 480px;
  28. height: calc(90vh - 2em);
  29. padding: 1em;
  30. -webkit-box-shadow: 10px 10px 18px 0px rgba(0,0,0,0.14);
  31. -moz-box-shadow: 10px 10px 18px 0px rgba(0,0,0,0.14);
  32. box-shadow: 10px 10px 18px 0px rgba(0,0,0,0.14);
  33. border-radius: 0.6em;
  34. border: 1px solid rgb(172, 172, 172);
  35. position: relative;
  36. background-color: white;
  37. }
  38. .divider{
  39. width: calc(100% - 4em);
  40. padding-top: 0.4em;
  41. margin-bottom: 0.4em;
  42. border-bottom: 1px solid rgb(226, 226, 226);
  43. padding-right: 2em;
  44. padding-left: 2em;
  45. }
  46. small{
  47. color: rgb(59, 59, 59);
  48. }
  49. .codeblock{
  50. padding: 0.6em;
  51. background-color: #242424;
  52. color: white;
  53. }
  54. /* Properties Table */
  55. .table_component {
  56. overflow: auto;
  57. width: 100%;
  58. }
  59. .table_component table {
  60. border: 1px solid #dededf;
  61. height: 100%;
  62. width: 100%;
  63. table-layout: fixed;
  64. border-collapse: collapse;
  65. border-spacing: 1px;
  66. text-align: left;
  67. }
  68. .table_component caption {
  69. caption-side: top;
  70. text-align: left;
  71. }
  72. .table_component th {
  73. border: 1px solid #dededf;
  74. background-color: #eceff1;
  75. color: #000000;
  76. padding: 5px;
  77. }
  78. .table_component td {
  79. border: 1px solid #dededf;
  80. background-color: #ffffff;
  81. color: #000000;
  82. padding: 5px;
  83. }
  84. /* Front Panel UI emulation */
  85. .controlEmu{
  86. position: absolute;
  87. right: 1.2em;
  88. bottom: 1.2em;
  89. padding: 1em;
  90. border-radius: 0.6em;
  91. background-color: #ececec;
  92. border: 1px solid rgb(197, 197, 197);
  93. }
  94. /* Power Button */
  95. #pwrbtn {
  96. display:block;
  97. height: 80px;
  98. width: 80px;
  99. border-radius: 50%;
  100. border: 1px solid rgba(156, 156, 156, 0.5);
  101. cursor: pointer;
  102. box-shadow: 10px 10px 18px 0px rgba(0,0,0,0.38);
  103. background-color: #f8f8f8;
  104. }
  105. #pwrbtn:hover{
  106. background-color: #c7c7c7;
  107. }
  108. #pwrbtn:active{
  109. background-color: #868686;
  110. box-shadow: inset 10px 10px 18px 0px rgba(0,0,0,0.38);
  111. }
  112. #pwrbtn svg{
  113. margin-top: 1.5em;
  114. margin-left: 0.1em;
  115. }
  116. /* Reset Button */
  117. #rstbtn {
  118. display:block;
  119. height: 40px;
  120. width: 40px;
  121. border-radius: 50%;
  122. border: 1px solid rgba(156, 156, 156, 0.5);
  123. cursor: pointer;
  124. margin-bottom: 1em;
  125. box-shadow: 10px 10px 18px 0px rgba(0,0,0,0.38);
  126. }
  127. #rstbtn svg{
  128. margin-top: 0.5em;
  129. margin-left: 0.1em;
  130. }
  131. #rstbtn:hover{
  132. background-color: #c7c7c7;
  133. }
  134. #rstbtn:active{
  135. background-color: #868686;
  136. box-shadow: inset 10px 10px 18px 0px rgba(0,0,0,0.38);
  137. }
  138. /* LEDs */
  139. .leds{
  140. margin-bottom: 1em;
  141. }
  142. .ledlabel{
  143. color: rgb(83, 83, 83);
  144. font-size: 0.8em;
  145. pointer-events: none;
  146. user-select: none;
  147. }
  148. .led {
  149. display:block;
  150. height: 10px;
  151. width: 10px;
  152. border-radius: 50%;
  153. background-color: #242424;
  154. }
  155. </style>
  156. </head>
  157. <body>
  158. <div class="wallpaper"></div>
  159. <br>
  160. <div class="box">
  161. <div class="main">
  162. <h2>🔌 ESPWoL Control Panel</h2>
  163. <p>Press a button on the bottom to power up / shutdown / reset your computer wirelessly</p>
  164. <div class="table_component" role="region" tabindex="0">
  165. <table>
  166. <thead>
  167. <tr>
  168. <th>Properties</th>
  169. <th>Status</th>
  170. </tr>
  171. </thead>
  172. <tbody>
  173. <tr>
  174. <td>
  175. <div>WLAN IP<br></div>
  176. </td>
  177. <td>0.0.0.0</td>
  178. </tr>
  179. <tr>
  180. <td>Power Status<br></td>
  181. <td id="powerLED">OFF</td>
  182. </tr>
  183. <tr>
  184. <td>HDD Status<br></td>
  185. <td id="hddStatus">IDLE</td>
  186. </tr>
  187. </tbody>
  188. </table>
  189. </div>
  190. <h3>🤖 RESTFUL API </h3>
  191. <p>You can also access the power status and controls via RESTFUL API requests.</p>
  192. <div class="codeblock"><code>
  193. GET /api/status <br>
  194. POST /api/power <br>
  195. POST /api/reset <br>
  196. </code></div>
  197. <br>
  198. <div class="divider"></div>
  199. <small>ESPWoL | Deisnged by tobychui 2023 - 2024</small>
  200. <div class="controlEmu" align="center">
  201. <div id="rstbtn" title="Reset Computer">
  202. <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M440-122q-121-15-200.5-105.5T160-440q0-66 26-126.5T260-672l57 57q-38 34-57.5 79T240-440q0 88 56 155.5T440-202v80Zm80 0v-80q87-16 143.5-83T720-440q0-100-70-170t-170-70h-3l44 44-56 56-140-140 140-140 56 56-44 44h3q134 0 227 93t93 227q0 121-79.5 211.5T520-122Z"/></svg>
  203. </div>
  204. <div class="leds">
  205. <div class="ledlabel">HDD <div class="led"></div></div><br>
  206. <div class="ledlabel">PWR <div class="led"></div></div>
  207. </div>
  208. <div id="pwrbtn" title="Power On / Off">
  209. <svg id="pwricon" fill="#eb4034" xmlns="http://www.w3.org/2000/svg" height="32" viewBox="0 -960 960 960" width="32"><path d="M440-440v-400h80v400h-80Zm40 320q-74 0-139.5-28.5T226-226q-49-49-77.5-114.5T120-480q0-80 33-151t93-123l56 56q-48 40-75 97t-27 121q0 116 82 198t198 82q117 0 198.5-82T760-480q0-64-26.5-121T658-698l56-56q60 52 93 123t33 151q0 74-28.5 139.5t-77 114.5q-48.5 49-114 77.5T480-120Z"/></svg>
  210. </div>
  211. </div>
  212. </div>
  213. </div>
  214. <script>
  215. /*
  216. The update interval will change based on the current status of the remote
  217. computer. By default, it update the status LED every seconds. When the
  218. remote is powered on, it update with 100ms delay between response and new requests.
  219. */
  220. let updateInterval = 1000;
  221. //Set the power status and hdd led status to off
  222. togglePowerState(false);
  223. toggleHDDLED(false);
  224. /* Read the status from server */
  225. function updateLEDStatus(){
  226. fetch('/status', {
  227. method: 'GET'
  228. })
  229. .then(response => {
  230. if (!response.ok) {
  231. throw new Error('Network error');
  232. updateInterval = 1000;
  233. setTimeout(updateLEDStatus, updateInterval);
  234. }
  235. return response.json();
  236. })
  237. .then(data => {
  238. //Update the power LED and update interval
  239. togglePowerState(data.pwr);
  240. if (data.pwr){
  241. updateInterval = 100;
  242. }else{
  243. updateInterval = 1000;
  244. }
  245. setTimeout(updateLEDStatus, updateInterval);
  246. //Update the hdd led
  247. toggleHDDLED(data.hdd);
  248. })
  249. }
  250. setTimeout(updateLEDStatus, updateInterval);
  251. /* Status LED Rendering */
  252. function togglePowerState(powerIsOn = true){
  253. if (powerIsOn){
  254. document.getElementById("powerLED").innerHTML = "🟢 ON";
  255. document.getElementById("pwricon").setAttribute("fill", "#7fe38b");
  256. }else{
  257. document.getElementById("powerLED").innerHTML = "⚫ OFF";
  258. document.getElementById("pwricon").setAttribute("fill", "#eb4034");
  259. }
  260. }
  261. function toggleHDDLED(hddLEDOn = true){
  262. if (hddLEDOn){
  263. document.getElementById("hddStatus").innerHTML = "🔵 R/W";
  264. }else{
  265. document.getElementById("hddStatus").innerHTML = "⚫ IDLE";
  266. }
  267. }
  268. /* Button Emulations */
  269. function handlePowerButtonPress(){
  270. fetch('/power/press', {
  271. method: 'GET'
  272. }).then(response => {
  273. if (!response.ok) {
  274. console.log("Error when trying to press power button")
  275. }
  276. });
  277. }
  278. function handlePowerButtonRelease(){
  279. fetch('/power/release', {
  280. method: 'GET'
  281. }).then(response => {
  282. if (!response.ok) {
  283. console.log("Error when trying to press power button")
  284. }
  285. });
  286. }
  287. function handleResetButtonPress(){
  288. fetch('/reset/press', {
  289. method: 'GET'
  290. }).then(response => {
  291. if (!response.ok) {
  292. console.log("Error when trying to press reset button")
  293. }
  294. });
  295. }
  296. function handlResetButtonRelease(){
  297. fetch('/reset/release', {
  298. method: 'GET'
  299. }).then(response => {
  300. if (!response.ok) {
  301. console.log("Error when trying to press reset button")
  302. }
  303. });
  304. }
  305. /* Bind events for the buttons */
  306. document.getElementById("pwrbtn").addEventListener("mousedown", handlePowerButtonPress);
  307. document.getElementById("pwrbtn").addEventListener("touchstart", handlePowerButtonPress);
  308. document.getElementById("pwrbtn").addEventListener("mouseup", handlePowerButtonRelease);
  309. document.getElementById("pwrbtn").addEventListener("touchend", handlePowerButtonRelease);
  310. document.getElementById("rstbtn").addEventListener("mousedown", handleResetButtonPress);
  311. document.getElementById("rstbtn").addEventListener("touchstart", handleResetButtonPress);
  312. document.getElementById("rstbtn").addEventListener("mouseup", handlResetButtonRelease);
  313. document.getElementById("rstbtn").addEventListener("touchend", handlResetButtonRelease);
  314. </script>
  315. </body>
  316. </html>