123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>ESPWoL</title>
- <style>
- body{
- font-family: Arial, sans-serif;
- color: #262626;
- }
- .box {
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .wallpaper{
- position: absolute;
- width: 100%;
- height: 100%;
- left: 0;
- top: 0;
- background-color: #ffffff;
- }
-
- .main{
- width: 480px;
- height: calc(90vh - 2em);
- padding: 1em;
- -webkit-box-shadow: 10px 10px 18px 0px rgba(0,0,0,0.14);
- -moz-box-shadow: 10px 10px 18px 0px rgba(0,0,0,0.14);
- box-shadow: 10px 10px 18px 0px rgba(0,0,0,0.14);
- border-radius: 0.6em;
- border: 1px solid rgb(172, 172, 172);
- position: relative;
- background-color: white;
- }
- .divider{
- width: calc(100% - 4em);
- padding-top: 0.4em;
- margin-bottom: 0.4em;
- border-bottom: 1px solid rgb(226, 226, 226);
- padding-right: 2em;
- padding-left: 2em;
- }
- small{
- color: rgb(59, 59, 59);
- }
- .codeblock{
- padding: 0.6em;
- background-color: #242424;
- color: white;
- }
- /* Properties Table */
- .table_component {
- overflow: auto;
- width: 100%;
- }
- .table_component table {
- border: 1px solid #dededf;
- height: 100%;
- width: 100%;
- table-layout: fixed;
- border-collapse: collapse;
- border-spacing: 1px;
- text-align: left;
- }
- .table_component caption {
- caption-side: top;
- text-align: left;
- }
- .table_component th {
- border: 1px solid #dededf;
- background-color: #eceff1;
- color: #000000;
- padding: 5px;
- }
- .table_component td {
- border: 1px solid #dededf;
- background-color: #ffffff;
- color: #000000;
- padding: 5px;
- }
- /* Front Panel UI emulation */
- .controlEmu{
- position: absolute;
- right: 1.2em;
- bottom: 1.2em;
- padding: 1em;
- border-radius: 0.6em;
- background-color: #ececec;
- border: 1px solid rgb(197, 197, 197);
- }
- /* Power Button */
- #pwrbtn {
- display:block;
- height: 80px;
- width: 80px;
- border-radius: 50%;
- border: 1px solid rgba(156, 156, 156, 0.5);
- cursor: pointer;
- box-shadow: 10px 10px 18px 0px rgba(0,0,0,0.38);
- background-color: #f8f8f8;
- }
- #pwrbtn:hover{
- background-color: #c7c7c7;
- }
- #pwrbtn:active{
- background-color: #868686;
- box-shadow: inset 10px 10px 18px 0px rgba(0,0,0,0.38);
- }
- #pwrbtn svg{
- margin-top: 1.5em;
- margin-left: 0.1em;
- }
- /* Reset Button */
- #rstbtn {
- display:block;
- height: 40px;
- width: 40px;
- border-radius: 50%;
- border: 1px solid rgba(156, 156, 156, 0.5);
- cursor: pointer;
- margin-bottom: 1em;
- box-shadow: 10px 10px 18px 0px rgba(0,0,0,0.38);
- }
- #rstbtn svg{
- margin-top: 0.5em;
- margin-left: 0.1em;
- }
- #rstbtn:hover{
- background-color: #c7c7c7;
- }
- #rstbtn:active{
- background-color: #868686;
- box-shadow: inset 10px 10px 18px 0px rgba(0,0,0,0.38);
- }
- /* LEDs */
- .leds{
- margin-bottom: 1em;
- }
- .ledlabel{
- color: rgb(83, 83, 83);
- font-size: 0.8em;
- pointer-events: none;
- user-select: none;
- }
- .led {
- display:block;
- height: 10px;
- width: 10px;
- border-radius: 50%;
- background-color: #242424;
- }
- /* status blinker */
- #statusBlinker{
- position: absolute;
- left: 1em;
- bottom: 1em;
- width: 1em;
- height: 2px;
- background-color: rgb(95, 95, 95);
- }
- #statusBlinker.interval{
- background-color: rgb(235, 235, 235);
- }
- </style>
- </head>
- <body>
- <div class="wallpaper"></div>
- <br>
- <div class="box">
- <div class="main">
- <h2>🔌 ESPWoL Control Panel</h2>
- <p>Press a button on the bottom to power up / shutdown / reset your computer wirelessly</p>
- <div class="table_component" role="region" tabindex="0">
- <table>
- <thead>
- <tr>
- <th>Properties</th>
- <th>Status</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>
- <div>WLAN IP<br></div>
- </td>
- <td id="wlanip"></td>
- </tr>
- <tr>
- <td>
- <div>mDNS Address<br></div>
- </td>
- <td id="mdnsaddr"></td>
- </tr>
- <tr>
- <td>Power Status<br></td>
- <td id="powerLED">OFF</td>
- </tr>
- <tr>
- <td>HDD Status<br></td>
- <td id="hddStatus">IDLE</td>
- </tr>
- </tbody>
- </table>
- </div>
- <h3>🤖 RESTFUL API / Magic Packet</h3>
- <p>You can also access the power status and controls via RESTFUL API requests or <a href="./wol">send WoL magic packet</a></p>
- <div class="codeblock"><code>
- GET /api/status <br>
- POST /api/power <br>
- POST /api/reset <br>
- </code></div>
- <br>
- <div class="divider"></div>
- <small>ESPWoL | Deisnged by tobychui 2023 - 2024</small>
- <div class="controlEmu" align="center">
- <div id="rstbtn" title="Reset Computer">
- <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>
- </div>
- <div class="leds">
- <div class="ledlabel">HDD <div class="led hddled"></div></div><br>
- <div class="ledlabel">PWR <div class="led powerled"></div></div>
- </div>
- <div id="pwrbtn" title="Power On / Off">
- <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>
- </div>
- </div>
- <div id="statusBlinker"></div>
- </div>
- </div>
- <script>
- /*
- The update interval will change based on the current status of the remote
- computer. By default, it update the status LED every seconds. When the
- remote is powered on, it update with 100ms delay between response and new requests.
- */
- let updateInterval = 1000;
- let statusBlinker = false; //Just an indicator to show connection is established
- //Set the power status and hdd led status to off
- togglePowerState(false);
- toggleHDDLED(false);
- /* Get the device ip and mdns */
- function initIPInfo(){
- fetch('/ipaddr', {
- method: 'GET'
- })
- .then(response => {
- if (!response.ok) {
- throw new Error('Network error');
- document.getElementById("wlanip").innerText = "192.168.4.1";
- document.getElementById("mdnsaddr").innerText = "Unknown";
- }
- return response.json();
- })
- .then(data => {
- document.getElementById("wlanip").innerText = data.ipaddr;
- document.getElementById("mdnsaddr").innerText = data.mdns;
- });
- }
- initIPInfo();
- /* Read the status from server */
- function updateLEDStatus(){
- fetch('/status', {
- method: 'GET'
- })
- .then(response => {
- if (!response.ok) {
- throw new Error('Network error');
- updateInterval = 1000;
- setTimeout(updateLEDStatus, updateInterval);
- }
- return response.json();
- })
- .then(data => {
- //Update the power LED and update interval
- togglePowerState(data.pwr);
- if (data.pwr){
- updateInterval = 100;
- }else{
- updateInterval = 1000;
- }
- setTimeout(updateLEDStatus, updateInterval);
- //Update the hdd led
- toggleHDDLED(data.hdd);
- //Update the status blinker
- statusBlinker = !statusBlinker;
- var blinker = document.getElementById("statusBlinker");
- if (statusBlinker){
- blinker.classList.add("interval");
- }else{
- blinker.classList.remove("interval");
- }
- })
- }
- setTimeout(updateLEDStatus, updateInterval);
- /* Status LED Rendering */
- function togglePowerState(powerIsOn = true){
- var powerLedIndicator = document.querySelectorAll('.powerled')[0];
- if (powerIsOn){
- document.getElementById("powerLED").innerHTML = "🟢 ON";
- document.getElementById("pwricon").setAttribute("fill", "#7fe38b");
- powerLedIndicator.style.backgroundColor = '#16c60c';
- }else{
- document.getElementById("powerLED").innerHTML = "⚫ OFF";
- document.getElementById("pwricon").setAttribute("fill", "#eb4034");
- powerLedIndicator.style.backgroundColor = '#383838';
- }
- }
- function toggleHDDLED(hddLEDOn = true){
- var hddLedIndicator = document.querySelectorAll('.hddled')[0];
- if (hddLEDOn){
- document.getElementById("hddStatus").innerHTML = "🔵 R/W";
- hddLedIndicator.style.backgroundColor = '#0078d7';
- }else{
- document.getElementById("hddStatus").innerHTML = "⚫ IDLE";
- hddLedIndicator.style.backgroundColor = '#383838';
- }
- }
- /* Button Emulations */
- function handlePowerButtonPress(){
- fetch('/power/press', {
- method: 'GET'
- }).then(response => {
- if (!response.ok) {
- console.log("Error when trying to press power button")
- }
- });
- }
- function handlePowerButtonRelease(){
- fetch('/power/release', {
- method: 'GET'
- }).then(response => {
- if (!response.ok) {
- console.log("Error when trying to press power button")
- }
- });
- }
- function handleResetButtonPress(){
- fetch('/reset/press', {
- method: 'GET'
- }).then(response => {
- if (!response.ok) {
- console.log("Error when trying to press reset button")
- }
- });
- }
- function handlResetButtonRelease(){
- fetch('/reset/release', {
- method: 'GET'
- }).then(response => {
- if (!response.ok) {
- console.log("Error when trying to press reset button")
- }
- });
- }
- /* Bind events for the buttons */
- document.getElementById("pwrbtn").addEventListener("mousedown", handlePowerButtonPress);
- document.getElementById("pwrbtn").addEventListener("touchstart", handlePowerButtonPress);
- document.getElementById("pwrbtn").addEventListener("mouseup", handlePowerButtonRelease);
- document.getElementById("pwrbtn").addEventListener("touchend", handlePowerButtonRelease);
- document.getElementById("rstbtn").addEventListener("mousedown", handleResetButtonPress);
- document.getElementById("rstbtn").addEventListener("touchstart", handleResetButtonPress);
- document.getElementById("rstbtn").addEventListener("mouseup", handlResetButtonRelease);
- document.getElementById("rstbtn").addEventListener("touchend", handlResetButtonRelease);
- </script>
- </body>
- </html>
|