<!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <title>Smart Switch</title> <meta name="viewport" content="width=device-width"> <link rel="apple-touch-icon" href="/favicon.ico" type="image/x-icon" /> <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /> <link rel="icon" href="/favicon.ico" type="image/x-icon" /> <link rel="stylesheet" href="app.css" type="text/css" /> <style> body { font-family: arial; color: #999 } table { margin: auto; max-width: 600px; } td { padding: 1%; padding-inline: 2% } [id^="input-"] { width: 70%; text-align: center; padding: 0px; box-sizing: border-box; border: none; border-bottom: 1px solid #2196f3; font-size: 22px; color: #2196f3; font-family: arial; } input[type=button] { background-color: #2196f3; border: none; color: #fff; padding: 10px 10px; width: 62px; text-decoration: none; margin: 4px 2px; cursor: pointer; border-radius: 34px; font-family: arial; font-weight: 700; -webkit-appearance: none; -moz-appearance: none; appearance: none; } .switch { position: relative; display: inline-block; width: 60px; height: 34px } .switch input { opacity: 0; width: 0; height: 0 } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; -webkit-transition: .4s; transition: .4s } .slider:before { position: absolute; content: ""; height: 26px; width: 26px; left: 4px; bottom: 4px; background-color: #fff; -webkit-transition: .4s; transition: .4s } input:checked+.slider { background-color: #2196f3 } input:focus+.slider { box-shadow: 0 0 1px #2196f3 } input:checked+.slider:before { -webkit-transform: translateX(26px); -ms-transform: translateX(26px); transform: translateX(26px) } .slider.round { border-radius: 34px } .slider.round:before { border-radius: 50% } .clk { font-size: 52px; color: #444; cursor: pointer } .clk2 { font-size: 24px; color: #444 } .clear:after, .clear:before { content: ""; display: table } .clear:after { clear: both } .wrapper { position: relative; top: 0px; right: 0; bottom: 0px; left: 0; margin: auto; max-width: 500px; text-align: center; border: 0px solid #ccc } .gauge { display: block; float: left } #g1, #g2 { width: 50% } .son { color: green; font-weight: bold } .soff { color: red; font-weight: bold } .blinking { animation: blinkingText 1.2s infinite; -webkit-animation: blinkingText 1.2s infinite; } @keyframes blinkingText { 0% { color: #ec0b0b; } 49% { color: #ea7272; } 60% { color: transparent; } 99% { color: transparent; } 100% { color: #ff0404; } } .container { display: inline-block; position: relative; padding-left: 19px; padding-top: 4px; margin-top: 8px; margin-bottom: 8px; cursor: pointer; font-size: 14px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; width: 12.5%; user-select: none } .container input { position: absolute; opacity: 0; cursor: pointer } .checkmark { position: absolute; top: 0; left: 0; height: 25px; width: 25px; background-color: #eee; border-radius: 50% } .container:hover input ~ .checkmark { background-color: #ccc } .container input:checked ~ .checkmark { background-color: #2196F3 } .checkmark:after { content: ""; position: absolute; display: none } .container input:checked ~ .checkmark:after { display: block } .container .checkmark:after { top: 6px; left: 6px; width: 13px; height: 13px; border-radius: 50%; background: white } *:focus {outline:none !important} </style> </head> <body> <table align="center"> <tr align="center"> <td colspan=3> <form name="sched"> <label class="container" id="LZ0">Def <input type="radio" name="radio" onclick="handleClick(this);" value="Z0"><span class="checkmark"></span></label> <label class="container" id="LZ1">M-F <input type="radio" name="radio" onclick="handleClick(this);" value="Z1"><span class="checkmark"></span></label> <label class="container" id="LZ2">Sat <input type="radio" name="radio" onclick="handleClick(this);" value="Z2"><span class="checkmark"></span></label> <label class="container" id="LZ3">Sun <input type="radio" name="radio" onclick="handleClick(this);" value="Z3"><span class="checkmark"></span></label> </form> </td> </tr> <tr align="center"> <td onmousedown="ent1Click();"> <label for="input-temperature">Temp °C</label> <input readonly="readonly" id="input-temperature" /> </td> <td onmousedown="ent2Click();"> <label for="input-popup-start">Time On</label> <input readonly="readonly" id="input-popup-start" /> </td> <td onmousedown="ent2Click();"> <label for="input-popup-stop">Time Off</label> <input readonly="readonly" id="input-popup-stop" /> </td> </tr> <tr align="center"> <td> <input type="button" id="W" value="Temp" onclick="button2Click(this);" /> </td> <td> <label class="switch"> <input id="cbStyle" type="checkbox" onclick="checkboxClick(this);"><span class="slider round"></span></label> </td> <td> <input type="button" id="T" value="Timer" onclick="buttonClick(this);" /> </td> </tr> <tr align="center"> <td> <div id="reconnect"> <input type="button" id="N" value="WSoff" onclick="statusWs();" /> </div> </td> <td><span id="sid"></span><div id="free-ram"></div><div id="erase-wifi"></div><div id="hw-reset"></div><div id="get-time"></div></td> <td> <div id="ebut"> <input type="button" id="E" value="WEdit" onclick="buttonEClick();" /> </div> </td> </tr> <tr align="center"> <td> <input type="button" id="X" value="xWiFi" onclick="loadDoc('erase-wifi', 1);"/> </td> <td> <input type="button" id="H" value="Heap" onclick="loadDoc('free-ram', 0);" /> </td> <td> <input type="button" id="R" value="HWrst" onclick="loadDoc('hw-reset', 1);"/> </td> </tr> </table> <div class="wrapper clear"> <div id="g1" class="gauge"></div> <div id="g2" class="gauge"></div> <div id="C" class="clk" onclick="getBtime();"></div> <div id="C2" class="clk2"></div> <input type="button" id="O" value="Logout" onclick="buttonOClick();" /> </div> <script src="app.min.js"></script> <script type="text/javascript"> const MYCORS = '192.168.1.12'; var g1, g2; var Analog0 = new Array(); var auto = true; const successNotification = window.createNotification({ positionClass: 'nfc-bottom-right', theme: 'info', showDuration: 3000 }); const warningNotification = window.createNotification({ positionClass: 'nfc-bottom-right', theme: 'warning', showDuration: 6000 }); document.addEventListener("DOMContentLoaded", function(event) { console.log("DOM fully loaded and parsed"); document.getElementById("R").style.backgroundColor = "red"; document.getElementById("X").style.backgroundColor = "red"; g1 = new JustGage({ id: "g1", value: -5.5, min: -40, max: 50, decimals: 1, labelFontColor: "#444", valueFontColor: "#444", title: "Temperature", titlePosition: "below", label: "°C", relativeGaugeSize: true, pointer: true, customSectors: [{ color: "#328da8", lo: -40, hi: 0 }, { color: "#32a852", lo: 0, hi: 35 }, { color: "#ff4d4d", lo: 35, hi: 50 }], formatNumber: true }); g2 = new JustGage({ id: "g2", value: 40.8, min: 0, max: 100, decimals: 1, labelFontColor: "#444", valueFontColor: "#444", title: "Humidity", titlePosition: "below", label: "%", relativeGaugeSize: true, pointer: true, customSectors: [{ color: "#ffc926", lo: 0, hi: 45 }, { color: "#32a852", lo: 45, hi: 55 }, { color: "#328da8", lo: 55, hi: 100 }], formatNumber: true }); }); var servurl = document.location.host; if (servurl.length < 5) servurl = MYCORS; var connection = new WebSocket('ws://' + servurl + '/ws', ['arduino']); connection.onopen = function() { //connection.send('get_something'); document.getElementById("sid").className = "son"; document.getElementById('sid').innerHTML = "Smart Switch"; console.log("connection opened"); }; connection.onclose = function() { document.getElementById("sid").className = "blinking"; document.getElementById('sid').innerHTML = "Detached"; document.getElementById("N").value = "WSon"; console.log("connection closed"); }; connection.onerror = function(error) { document.getElementById("sid").className = "soff"; document.getElementById('sid').innerHTML = "Detached"; document.getElementById("N").value = "WSon"; console.log('WebSocket Error ', error); }; connection.onmessage = function(evt) { // handle websocket message. update attributes or values of elements that match the name on incoming message console.log("msg rec", evt.data); var msgArray = evt.data.split(","); // split message by delimiter into a string array console.log("msgArray", msgArray[0]); console.log("msgArray", msgArray[1]); console.log("msgArray", msgArray[2]); console.log("msgArray", msgArray[3]); console.log("msgArray", msgArray[4]); var indicator = msgArray[1]; // the first element in the message array is the ID of the object to update console.log("indiactor", indicator); var a = document.getElementById('cbStyle'); if (indicator) // if an object by the name of the message exists, update its value or its attributes { switch (msgArray[1]) { case "Arduino": console.log("Got Temp / Humidity"); g1.refresh(msgArray[2], null); g2.refresh(msgArray[3], null); if (msgArray[4] == "1") document.getElementById("T").style.backgroundColor = "#32a852"; else document.getElementById("T").style.backgroundColor = "#2196f3"; var delta = (parseFloat(document.getElementById('input-temperature').value).toFixed(1) - parseFloat(msgArray[2]).toFixed(1)); if (delta > 0.5) document.getElementById("W").style.backgroundColor = "red"; else if (delta < -0.5) document.getElementById("W").style.backgroundColor = "#2196f3"; break; case "Clock": var dn = parseInt(msgArray[3]); var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; var dayName = days[dn] || '*'; // 0...6 var shedtype = 0; if (dn == 0) shedtype = 3; else if (dn == 6) shedtype = 2; else if ((dn > 0) && (dn < 6)) shedtype = 1; document.getElementById('C').innerHTML = msgArray[2]; document.getElementById('C2').innerHTML = dayName; if (auto) document.getElementById('LZ' + shedtype).classList.add('son'); else document.getElementById('LZ' + shedtype).classList.remove('son'); break; case "Setting": document.getElementById('input-popup-start').value = msgArray[2]; document.getElementById('input-popup-stop').value = msgArray[3]; document.getElementById('input-temperature').value = parseFloat(msgArray[4]).toFixed(1); document.getElementById('input-popup-start').className = ""; document.getElementById('input-popup-stop').className = ""; document.getElementById('input-temperature').className = ""; tpick.attach("input-popup-start"); tpick.attach("input-popup-stop"); fpick.attach("input-temperature"); warningNotification({ message: 'Client UPD' }); break; case "ledon": a.checked = true; break; case "ledoff": a.checked = false; break; case "remoff": successNotification({ message: 'Client quit' }); break; case "OTA": warningNotification({ message: 'OTA begin' }); statusWs(); break; case "sched": document.sched.radio[msgArray[2]].checked = true; break; default: // unrecognized message type. do nothing break; } // switch } // if (indicator) }; // connection.onmessage function buttonClick(e) { if (connection.readyState === WebSocket.OPEN) { connection.send(e.id + document.getElementById("input-popup-start").value + "|" + document.getElementById("input-popup-stop").value + "|"); successNotification({ message: 'Timer REQ' }); } } function button2Click(e) { if (connection.readyState === WebSocket.OPEN) { connection.send(e.id + parseFloat(document.getElementById("input-temperature").value).toFixed(1) + "|"); successNotification({ message: 'Temp. REQ' }); } } function buttonEClick() { var murl = '/edit'; if (document.location.host.length < 5) murl = 'http://' + MYCORS + '/edit'; //CORS successNotification({message: 'Editor'}); window.open(murl, '_blank'); } function buttonOClick() { var murl = ""; // If base auth //murl = document.location.href.replace("http://", "http://" + new Date().getTime() + "@"); // If cookie auth murl += 'login/'; if (document.location.host.length < 5) murl = 'http://' + MYCORS + '/login/'; //CORS warningNotification({ message: 'Logout'}); window.open(murl, '_self'); } function checkboxClick(e) { if (connection.readyState === WebSocket.OPEN) { if (e.checked) connection.send('L1'); else connection.send('L0'); } } function ent1Click() { document.getElementById("input-temperature").className = "blinking"; } function ent2Click() { document.getElementById("input-popup-stop").className = "blinking"; document.getElementById("input-popup-start").className = "blinking"; } function handleClick(e) { if (e.value == 'Z0' ) auto = true; else auto = false; document.getElementById('L' + e.value).classList.remove('son'); if (connection.readyState === WebSocket.OPEN) connection.send(e.value + "|"); } // XMLHttpRequest /non WebSocket/ command. same as command' div' id to get response to function loadDoc(cmd, r, param) { var par = param || ''; var murl = '/' + cmd + par; if (document.location.host.length < 5) murl = 'http://' + MYCORS + '/' + cmd + par; //CORS var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById(cmd).innerHTML = this.responseText; } }; xhttp.open("GET", murl, true); xhttp.send(); successNotification({ message: 'Cmd: ' + cmd }); if (r) { //restart? connection.close(); document.getElementById("N").value = "WSon"; } }; function getBtime() { loadDoc('get-time', 0, '?btime=' + Math.round(new Date().getTime()/1000)); document.getElementById('C').innerHTML =''; document.getElementById('C2').innerHTML =''; window.location.reload(); } function statusWs() { if (connection.readyState === WebSocket.OPEN) { connection.close(); document.getElementById("N").value = "WSon"; warningNotification({ message: 'WS Closed'}); } else { window.location.reload(); } }; </script> </body> </html>