Files
NTUhrVPx/index_html.h
2025-08-24 09:11:23 +02:00

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";