566 lines
17 KiB
C++
566 lines
17 KiB
C++
const char html_page_index[] PROGMEM = R"rawliteral(
|
|
<!DOCTYPE HTML><html>
|
|
<head>
|
|
<title>N-Tools.de Uhr</title>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta charset="UTF-8">
|
|
<link rel="icon" href="data:,">
|
|
<style>
|
|
html {font-family: Roboto, Arial; display: inline-block; text-align: center;}
|
|
body {font-size: 1.5rem; margin:0px auto; padding-bottom: 25px; min-height:100%;}
|
|
body * {font-size: 1.3rem;}
|
|
input[type=checkbox]{
|
|
transform: scale(1.5);
|
|
padding: 10px;
|
|
position: relative;
|
|
}
|
|
label {min-width: 150px;display: inline-block;text-align: left; padding-left: 5px;}
|
|
input,select,option { display: inline-block;text-align:center;}
|
|
h1,h2,h3{padding:0px;margin:0px;)}
|
|
h1{font-size: 1.7rem;}
|
|
.head{
|
|
background: linear-gradient(to bottom, #1b62d8 0%, #003399 100%);
|
|
text-align: right;
|
|
margin: 0px;
|
|
padding: 5px;
|
|
box-shadow: 0 8px 32px 0 rgb(0 0 0 / 40%), 0 3px 20px 0 rgb(0 0 0 / 38%);
|
|
color:#fff;
|
|
}
|
|
.site{
|
|
|
|
}
|
|
.option {
|
|
margin: 20px;
|
|
padding: 10px;
|
|
box-shadow: 0 16px 32px 0 rgb(0 0 0 / 40%), 0 6px 20px 0 rgb(0 0 0 / 38%);
|
|
min-width: 160px;
|
|
border-radius: 4px;
|
|
background-color: #fff;
|
|
display: inline-grid;
|
|
text-align: center;
|
|
overflow: hidden;
|
|
opacity: 0.8;
|
|
}
|
|
.value {
|
|
cursor: pointer;
|
|
display: block;
|
|
}
|
|
.act{
|
|
background-color: #000;
|
|
color: #fff;
|
|
padding: 2px 5px 2px 5px;
|
|
}
|
|
.m50{
|
|
min-width: 50%;
|
|
}
|
|
.fs25{
|
|
font-size: 2.5rem;
|
|
}
|
|
.fs12{
|
|
font-size: 1.2rem;
|
|
}
|
|
.fs17{
|
|
font-size: 1.7rem;
|
|
}
|
|
.fs075, .fs075 *{
|
|
font-size: 0.75rem;
|
|
}
|
|
.left{
|
|
text-align: left;
|
|
}
|
|
.margin25left{
|
|
margin-left: 25%;
|
|
}
|
|
.margin12left{
|
|
margin-left: 12%;
|
|
}
|
|
#te{
|
|
display: none;
|
|
position: fixed;
|
|
top: 10%;
|
|
left: 10%;
|
|
margin: auto;
|
|
padding: 3%;
|
|
box-shadow: 0 16px 32px 0 rgb(0 0 0 / 40%), 0 6px 20px 0 rgb(0 0 0 / 38%);
|
|
min-height: 70%;
|
|
width: 74%;
|
|
border-radius: 8px;
|
|
background-color: #fff;
|
|
text-align: center;
|
|
overflow: hidden;
|
|
opacity: 1.0;
|
|
}
|
|
#te > .value{
|
|
text-align: left;
|
|
}
|
|
#oe{
|
|
display: none;
|
|
position: fixed;
|
|
top: 10%;
|
|
left: 10%;
|
|
margin: auto;
|
|
padding: 3%;
|
|
box-shadow: 0 16px 32px 0 rgb(0 0 0 / 40%), 0 6px 20px 0 rgb(0 0 0 / 38%);
|
|
min-height: 70%;
|
|
width: 74%;
|
|
border-radius: 8px;
|
|
background-color: #fff;
|
|
text-align: center;
|
|
overflow: hidden;
|
|
opacity: 1.0;
|
|
}
|
|
#oe > .value{
|
|
text-align: left;
|
|
}
|
|
#close{
|
|
cursor: pointer;
|
|
text-align: right;
|
|
display: block;
|
|
}
|
|
#message{
|
|
display: none;
|
|
position: fixed;
|
|
top: 10%;
|
|
left: 35%;
|
|
margin: auto;
|
|
padding: 5px;
|
|
box-shadow: 0 16px 32px 0 rgb(0 0 0 / 40%), 0 6px 20px 0 rgb(0 0 0 / 38%);
|
|
width: 30%;
|
|
border-radius: 4px;
|
|
z-index: 9999;
|
|
}
|
|
|
|
input[type=button], input[type=submit], input[type=reset] {
|
|
background-color: #1b62d8;
|
|
border: none;
|
|
cursor: pointer;
|
|
|
|
color: #fff;
|
|
position: relative;
|
|
text-decoration: none;
|
|
text-transform: uppercase;
|
|
padding: 0.25rem 0.5rem;
|
|
@media(min-width: 600px) {
|
|
margin: 0 1em 2em;
|
|
}
|
|
|
|
&:hover { text-decoration: none; }
|
|
|
|
box-shadow: inset 0 0 20px rgba(255, 255, 255, 0);
|
|
outline: 1px solid;
|
|
outline-color: rgba(255, 255, 255, .5);
|
|
outline-offset: 0px;
|
|
text-shadow: none;
|
|
|
|
border-radius: 4px;
|
|
}
|
|
|
|
input[type=button]:hover {
|
|
box-shadow: 0 16px 32px 0 rgb(0 0 0 / 40%), 0 6px 20px 0 rgb(0 0 0 / 38%);
|
|
outline-color: rgba(255, 255, 255, 0);
|
|
outline-offset: 15px;
|
|
text-shadow: 1px 1px 2px #427388;
|
|
}
|
|
.wsnw{
|
|
white-space: nowrap;
|
|
}
|
|
.center{
|
|
text-align: center;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="head" class="head">
|
|
<h1>N-Tools Uhr VPx</h1>
|
|
<h3>`VERSION`</h3>
|
|
<h3>`ID`</h3>
|
|
<span style='font-size: 0.7rem;'>lokale IP: `LOCALIP`</span>
|
|
</div>
|
|
<div id="site" class="site">
|
|
<div id="message"></div>
|
|
<div class='option' onclick="editTime(-1);">
|
|
<div class='value'>
|
|
<label class="center">aktuell:</label><br>
|
|
<span class='act' id="actTime"></span><br>
|
|
<span class='act' id="actTacTime"></span><br>
|
|
<span class='act' id="actDate"></span><br>
|
|
<span class='act' id="actKW"></span>
|
|
</div><br>
|
|
<div class='fs075'>
|
|
<label>letzter abgleich:</label>
|
|
<span id="sync"></span>
|
|
</div>
|
|
</div><br>
|
|
<br>
|
|
<div class='option m50'>
|
|
<label for="showWhat">Zeige</label>
|
|
<select id="showWhat" onchange="setShowWhat();">
|
|
<option value=0>taktische Uhrzeit</option>
|
|
<option value=1>Uhrzeit</option>
|
|
<option value=2>Datum / Uhrzeit</option>
|
|
<option value=3>Analoguhr</option>
|
|
<option value=4>Analoguhr / Datum</option>
|
|
</select>
|
|
</div>
|
|
<div class='option m50' onclick="return false">
|
|
<span class="wsnw">
|
|
<label for="brigtness">Helligkeit LEDs</label>
|
|
<span><span id="brigtness"></span> %</span><br>
|
|
</span>
|
|
<span class="wsnw">
|
|
<label for="temp">Temperatur Elektronik</label>
|
|
<span><span id="temp"></span>° C</span><br>
|
|
</span>
|
|
<div class="left">
|
|
<span class="wsnw">
|
|
<label for="SSID">SSID:</label>
|
|
<span id="SSID"></span>
|
|
</span>
|
|
<br>
|
|
<input type="button" onclick="editOption();" value="Optionen ändern"><br>
|
|
<br>
|
|
<span class="wsnw">
|
|
<input id="rtcactive" type='checkbox' onclick="return false" readonly>
|
|
<label for="rtcactive">RTC okay</label>
|
|
</span>
|
|
<span class="wsnw">
|
|
<input id="withSeconds" type='checkbox' onclick="return false" readonly>
|
|
<label for="withSeconds">Sekunden zeigen</label>
|
|
</span>
|
|
<span class="wsnw">
|
|
<input id="isSummerTime" type='checkbox' onclick="return false" readonly>
|
|
<label for="isSummerTime">Sommerzeit</label>
|
|
</span>
|
|
<span class="wsnw">
|
|
<input id="alwaysAccessPoint" type='checkbox' onclick="return false" readonly>
|
|
<label for="alwaysAccessPoint">AccessPoint erstellen auch bei erfolgreicher WiFi Verbindung</label>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<input id="d" type='text' style='width:80%;font-size:0.75rem;display:none;' value=''>
|
|
<div class='option m50'>
|
|
<input class="fs17" id="save" class="btn" type='button' value='dauerhaft speichern' onclick='save();'>
|
|
</div>
|
|
<div class='option m50'>
|
|
<input class="fs17" id="reset" class="btn" type='button' value='neu starten' onclick='reset();'>
|
|
</div>
|
|
<div id="te">
|
|
<div id="close" onclick="closeEdit();">X</div>
|
|
<div class='value'>
|
|
<h1><span id="el"></span></h1>
|
|
<label for="eActTimeC">Uhrzeit: </label><input type="color" id="eActTimeC" value=""><br>
|
|
<label for="eActTacTimeC">taktische Zeit: </label><input type="color" id="eActTacTimeC" value=""><br>
|
|
<label for="eActDateC">Datum: </label><input type="color" id="eActDateC" value=""><br>
|
|
<label for="eActKWC">KW: </label><input type="color" id="eActKWC" value=""><br>
|
|
<input type="button" class="btn fs12" onclick="setColor();closeEdit();" value="setzen"><br><br>
|
|
<input type="button" id="doSetTime" class="btn fs12" onclick="doSetTime();" value="Uhrzeit nach diesem Gerät setzen"><br>
|
|
|
|
</div>
|
|
</div>
|
|
<div id="oe">
|
|
<div id="close" onclick="closeOptionEdit();">X</div>
|
|
<div class='value'>
|
|
<h1><span id="el">Optionen</span></h1>
|
|
<input id="ebs" type='number' min="5" max="100" step="5"> %
|
|
<label for="ebs">Helligkeitsfaktor (in Prozent)</label><br>
|
|
<span>
|
|
<input id="eWithSeconds" type='checkbox'>
|
|
<label for="eWithSeconds">zeige Sekunden</label>
|
|
</span>
|
|
<span>
|
|
<input id="eAlwaysAccessPoint" type='checkbox'>
|
|
<label for="eAlwaysAccessPoint">AccessPoint erstellen auch bei erfolgreicher WiFi Verbindung</label>
|
|
</span>
|
|
<br>
|
|
<input type="button" class="btn" onclick="setOption();" value="setzen">
|
|
<br><br>
|
|
<span>
|
|
<label for="eSSID">SSID:</label>
|
|
<input id="eSSID" type='text' onclick="return false">
|
|
</span>
|
|
<br>
|
|
<span>
|
|
<label for="ePASS">Passwort:</label>
|
|
<input id="ePASS" type='text' onclick="return false">
|
|
</span>
|
|
<br>
|
|
<input type="button" class="btn" onclick="setWifi();" value="setzen">
|
|
<br><br>
|
|
<span>
|
|
<label for="apPASS">AccessPoint Passwort:</label>
|
|
<input id="apPASS" type='text' maxlength="64" minlength="8" onclick="return false">
|
|
</span>
|
|
<br>
|
|
<input type="button" class="btn" onclick="setAPPass();" value="setzen"><br>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
|
|
var ti = new Date;
|
|
var EEPROMDataChanged = false;
|
|
|
|
function RGBToHex(rgb) {
|
|
// Choose correct separator
|
|
let sep = rgb.indexOf(",") > -1 ? "," : " ";
|
|
// Turn "rgb(r,g,b)" into [r,g,b]
|
|
rgb = rgb.substr(4).split(")")[0].split(sep);
|
|
|
|
let r = (+rgb[0]).toString(16),
|
|
g = (+rgb[1]).toString(16),
|
|
b = (+rgb[2]).toString(16);
|
|
|
|
if (r.length == 1)
|
|
r = "0" + r;
|
|
if (g.length == 1)
|
|
g = "0" + g;
|
|
if (b.length == 1)
|
|
b = "0" + b;
|
|
console.log("#" + r + g + b);
|
|
return "#" + r + g + b;
|
|
}
|
|
|
|
|
|
function closeEdit(){
|
|
document.getElementById("te").style.display = "none";
|
|
}
|
|
|
|
function editTime(_what){
|
|
if(_what == -1){
|
|
document.getElementById("el").innerHTML = 'Farben';
|
|
document.getElementById("eActTimeC").value = RGBToHex(document.getElementById('actTime').style.color);
|
|
document.getElementById("eActTacTimeC").value = RGBToHex(document.getElementById('actTacTime').style.color);
|
|
document.getElementById("eActDateC").value = RGBToHex(document.getElementById('actDate').style.color);
|
|
document.getElementById("eActKWC").value = RGBToHex(document.getElementById('actKW').style.color);
|
|
}
|
|
document.getElementById("te").style.display = "initial";
|
|
}
|
|
|
|
function closeOptionEdit(){
|
|
document.getElementById("oe").style.display = "none";
|
|
}
|
|
|
|
function editOption(){
|
|
document.getElementById('ebs').value = document.getElementById('brigtness').innerHTML;
|
|
document.getElementById('eSSID').value = document.getElementById('SSID').innerHTML;
|
|
document.getElementById("eWithSeconds").checked = document.getElementById("withSeconds").checked;
|
|
document.getElementById("eAlwaysAccessPoint").checked = document.getElementById("alwaysAccessPoint").checked;
|
|
document.getElementById("oe").style.display = "initial";
|
|
}
|
|
|
|
Number.prototype.AddZero= function(b,c){
|
|
var l= (String(b || 10).length - String(this).length)+1;
|
|
return l>0? new Array(l).join(c || '0')+this : this;
|
|
}
|
|
|
|
function showOK(){
|
|
document.getElementById("message").innerHTML='ok';
|
|
document.getElementById("message").style.backgroundColor = "#0f0";
|
|
document.getElementById("message").style.display = "initial";
|
|
setTimeout(function(){
|
|
document.getElementById("message").style.display = "none";
|
|
}, 2000);
|
|
}
|
|
|
|
function fetchHandle(res){
|
|
if(!res.ok){
|
|
console.log(res);
|
|
document.getElementById("site").style.backgroundColor = "#f00";
|
|
}else{
|
|
if(EEPROMDataChanged)
|
|
document.getElementById("site").style.backgroundColor = "#ffa";
|
|
else
|
|
document.getElementById("site").style.backgroundColor = "#fff";
|
|
return res;
|
|
}
|
|
}
|
|
|
|
function fetch_handle_response(res){
|
|
var elem=document.getElementById('d');
|
|
elem.value=res;
|
|
if(res == 'OK'){
|
|
showOK();
|
|
}else if(res[0] == '['){
|
|
try{
|
|
var data = JSON.parse(res);
|
|
ti = data[0];
|
|
showAktTimeFromUnix(ti);
|
|
colorString = "#" + data[1].toString(16).padStart(6, '0');
|
|
document.getElementById('actTime').style.color = colorString;
|
|
colorString = "#" + data[2].toString(16).padStart(6, '0');
|
|
document.getElementById('actTacTime').style.color = colorString;
|
|
colorString = "#" + data[3].toString(16).padStart(6, '0');
|
|
document.getElementById('actDate').style.color = colorString;
|
|
|
|
document.getElementById('showWhat').value = parseInt(data[4]);
|
|
switch(data[5]){
|
|
case 0:
|
|
document.getElementById('sync').innerHTML = " keiner";
|
|
break;
|
|
case 1:
|
|
document.getElementById('sync').innerHTML += " (GPS)";
|
|
break;
|
|
case 2:
|
|
document.getElementById('sync').innerHTML += " (NTP)";
|
|
break;
|
|
case 3:
|
|
document.getElementById('sync').innerHTML += " (manuel)";
|
|
break;
|
|
}
|
|
showTimeFromUnix(data[6],'sync');
|
|
document.getElementById('brigtness').innerHTML = (data[7]*100);
|
|
document.getElementById("rtcactive").checked = (data[8] == 1);
|
|
|
|
EEPROMDataChanged = (data[9] == 1);
|
|
if(EEPROMDataChanged){
|
|
document.getElementById("site").style.backgroundColor = "#ffa";
|
|
}
|
|
document.getElementById('SSID').innerHTML = data[10];
|
|
document.getElementById('temp').innerHTML = data[11];
|
|
var options = parseInt(data[12]);
|
|
document.getElementById("withSeconds").checked = (options >> 0) & 0x1;
|
|
document.getElementById("alwaysAccessPoint").checked = (options >> 1) & 0x1;
|
|
|
|
colorString = "#" + data[13].toString(16).padStart(6, '0');
|
|
document.getElementById('actKW').style.color = colorString;
|
|
document.getElementById('actKW').innerHTML = "KW " + data[14];
|
|
document.getElementById("isSummerTime").checked = (data[15] == 1);
|
|
}catch(e){
|
|
console.log(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
function doSend(_value1,_value2=[],_value3=[]){
|
|
var send_str = "/do?"+_value1[0]+"="+_value1[1];
|
|
if(_value2.length > 0){
|
|
send_str += "&"+_value2[0]+"="+_value2[1];
|
|
}
|
|
if(_value3.length > 0){
|
|
send_str += "&"+_value3[0]+"="+_value3[1];
|
|
}
|
|
fetch(send_str).then(fetchHandle).then((res) => res.text()).then((text) => fetch_handle_response(text)).catch((err) => { console.log(err);document.getElementById("site").style.backgroundColor = "#f00";});
|
|
}
|
|
|
|
function doPoll(){
|
|
var send_str = "/poll";
|
|
fetch(send_str).then(fetchHandle).then((res) => res.text()).then((text) => fetch_handle_response(text)).catch((err) => { console.log(err);document.getElementById("site").style.backgroundColor = "#f00";});
|
|
}
|
|
|
|
function doSetTime(_idx = -1){
|
|
var d=new Date();
|
|
d.setTime(d.getTime() - (d.getTimezoneOffset()*60*1000) + 1000);
|
|
doSend(['set','time'],['to',Math.floor(d /1000)],['idx',_idx]);
|
|
}
|
|
|
|
function setColor(){
|
|
var elem=document.getElementById('eActTimeC');
|
|
doSend(['set','color'],['to',elem.value.substring(1)]);
|
|
elem=document.getElementById('eActTacTimeC');
|
|
doSend(['set','tcolor'],['to',elem.value.substring(1)]);
|
|
elem=document.getElementById('eActDateC');
|
|
doSend(['set','dcolor'],['to',elem.value.substring(1)]);
|
|
elem=document.getElementById('eActKWC');
|
|
doSend(['set','kwcolor'],['to',elem.value.substring(1)]);
|
|
}
|
|
|
|
function setTimeFromUnix(_ti,_id){
|
|
var elem=document.getElementById(_id);
|
|
//var st = String(new Date(_ti*1000).toISOString().substr(0,19));
|
|
var st = new Date(parseInt(_ti) * 1000);
|
|
var sst = st.toISOString().slice(0,19);
|
|
elem.value = sst;
|
|
}
|
|
|
|
function showAktTimeFromUnix(_ti){
|
|
var elem=document.getElementById('actTime');
|
|
var elem2=document.getElementById('actTacTime');
|
|
var elem3=document.getElementById('actDate');
|
|
var st = new Date(parseInt(_ti) * 1000);
|
|
st.setTime(st.getTime() + (st.getTimezoneOffset()*60*1000));
|
|
//var sst = st.toUTCString();
|
|
var sstTime = ("0" + st.getHours()).slice(-2) + ":" + ("0" + st.getMinutes()).slice(-2) + ":" + ("0" + st.getSeconds()).slice(-2);
|
|
elem.innerHTML = sstTime;
|
|
const formatter = new Intl.DateTimeFormat('en', { month: 'short' });
|
|
const month = formatter.format(st);
|
|
var sstTacTime = ("0" + st.getDate()).slice(-2) + "" + ("0" + st.getHours()).slice(-2) + "" + ("0" + st.getMinutes()).slice(-2) + month.toLowerCase() + ("" + st.getFullYear()).slice(-2);
|
|
elem2.innerHTML = sstTacTime;
|
|
var sstDate = ("0" + st.getDate()).slice(-2) + "." + ("0"+(st.getMonth()+1)).slice(-2) + "." +st.getFullYear();
|
|
elem3.innerHTML = sstDate;
|
|
}
|
|
|
|
function showTimeFromUnix(_ti,_id){
|
|
var elem=document.getElementById(_id);
|
|
var st = new Date(parseInt(_ti) * 1000);
|
|
st.setTime(st.getTime() + (st.getTimezoneOffset()*60*1000));
|
|
//var sst = st.toUTCString();
|
|
var sst = ("0" + st.getDate()).slice(-2) + "." + ("0"+(st.getMonth()+1)).slice(-2) + "." +st.getFullYear() + " " + ("0" + st.getHours()).slice(-2) + ":" + ("0" + st.getMinutes()).slice(-2) + ":" + ("0" + st.getSeconds()).slice(-2);
|
|
elem.innerHTML = sst;
|
|
}
|
|
|
|
function setShowWhat(_what = -2){
|
|
if(_what == -2){
|
|
var elem=document.getElementById("showWhat");
|
|
doSend(['set','option'],['showWhat',elem.value]);
|
|
}else{
|
|
doSend(['set','option'],['showWhat',_what]);
|
|
}
|
|
}
|
|
|
|
function setBrightness(){
|
|
var elem=document.getElementById("ebs");
|
|
doSend(['set','option'],['brightness',(elem.value / 100)]);
|
|
}
|
|
|
|
function setWifi(){
|
|
var elem=document.getElementById("eSSID");
|
|
var elem2=document.getElementById("ePASS");
|
|
doSend(['set','wifi'],['ssid',encodeURIComponent(elem.value)],['pwd',encodeURIComponent(elem2.value)]);
|
|
}
|
|
|
|
function setAPPass(){
|
|
var elem=document.getElementById("apPASS");
|
|
var pwd = String(elem.value);
|
|
if((pwd.length > 7) && (pwd.length < 65)){
|
|
doSend(['set','appass'],['pwd',encodeURIComponent(pwd)]);
|
|
elem.value = '';
|
|
}else{
|
|
alert('Das AccessPoint Passwort muss zwischen 8 und 64 Zeichen lang sein!');
|
|
}
|
|
}
|
|
|
|
function setOption(){
|
|
setBrightness();
|
|
var option = 0;
|
|
if(document.getElementById("eWithSeconds").checked)
|
|
option += 1;
|
|
if(document.getElementById("eAlwaysAccessPoint").checked)
|
|
option += 2;
|
|
|
|
doSend(['set','option'],['options',option]);
|
|
}
|
|
|
|
function save() {
|
|
doSend(['save','']);
|
|
}
|
|
|
|
function reset() {
|
|
doSend(['reset','']);
|
|
}
|
|
|
|
function poll() {
|
|
doPoll();
|
|
setTimeout(function(){
|
|
poll();
|
|
}, 1000);
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", function(event) {
|
|
poll();
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|
|
)rawliteral";
|