Compare commits

..

No commits in common. "096849b6efbbde4658b9174e495272ef5e570149" and "3aabfcd58ed6953fb12a8d17e2a160cf884e6a00" have entirely different histories.

14 changed files with 749 additions and 1263 deletions

1
.gitattributes vendored
View file

@ -1 +0,0 @@
* -text

View file

@ -1,70 +1,70 @@
<div id="tab-config" class=""> <div id="tab-config" class="">
<form class="pure-form pure-form-aligned" action="/" method="post"> <form class="pure-form pure-form-aligned" action="/" method="post">
<br> <br>
<label for="startup"> <label for="startup">
<strong>Light initialization</strong> <strong>Light initialization</strong>
</label> </label>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="startup"> <label for="startup">
<strong>Startup</strong> <strong>Startup</strong>
</label> </label>
<select onchange="this.form.submit()" id="startup" name="startup"> <select onchange="this.form.submit()" id="startup" name="startup">
<option {{STARTUP_SELECTED_LS_0}} value="0">Last state</option> <option {{STARTUP_SELECTED_LS_0}} value="0">Last state</option>
<option {{STARTUP_SELECTED_ON_1}} value="1">On</option> <option {{STARTUP_SELECTED_ON_1}} value="1">On</option>
<option {{STARTUP_SELECTED_OFF_2}} value="2">Off</option> <option {{STARTUP_SELECTED_OFF_2}} value="2">Off</option>
</select> </select>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="scene"> <label for="scene">
<strong>Scene</strong> <strong>Scene</strong>
</label> </label>
<select onchange="this.form.submit()" id="scene" name="scene"> <select onchange="this.form.submit()" id="scene" name="scene">
<option {{SCENE_SELECTED_RELAX_0}} value="0">Relax</option> <option {{SCENE_SELECTED_RELAX_0}} value="0">Relax</option>
<option {{SCENE_SELECTED_BRIGHT_1}} value="1">Bright</option> <option {{SCENE_SELECTED_BRIGHT_1}} value="1">Bright</option>
<option {{SCENE_SELECTED_NIGHT_2}} value="2">Night</option> <option {{SCENE_SELECTED_NIGHT_2}} value="2">Night</option>
</select> </select>
</div> </div>
<br> <br>
<label for="startup"> <label for="startup">
<strong>Wifi</strong> <strong>Wifi</strong>
</label> </label>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="ip">SSID</label> <label for="ip">SSID</label>
<input id="ssid" name="ssid" type="text" value="{{WIFI_SSID}}"> <input id="ssid" name="ssid" type="text" value="{{WIFI_SSID}}">
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="wpw">Passphrase</label> <label for="wpw">Passphrase</label>
<input id="wpw" name="wpw" type="text" placeholder="1234password"> <input id="wpw" name="wpw" type="text" placeholder="1234password">
</div> </div>
<br> <br>
<label for="startup"> <label for="startup">
<strong>Network</strong> <strong>Network</strong>
</label> </label>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="dip"> <label for="dip">
<strong>Dynamic-IP</strong> <strong>Dynamic-IP</strong>
</label> </label>
<a class="pure-button {{DIP_LINK_ON_PRIMARY}}" href="/?dip=true">ON</a> <a class="pure-button {{DIP_LINK_ON_PRIMARY}}" href="/?dip=true">ON</a>
<a class="pure-button {{DIP_LINK_OFF_PRIMARY}}" href="/?dip=false">OFF</a> <a class="pure-button {{DIP_LINK_OFF_PRIMARY}}" href="/?dip=false">OFF</a>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="ip">IP</label> <label for="ip">IP</label>
<input id="ip" name="ip" type="text" value="{{WIFI_CFG_IP}}"> <input id="ip" name="ip" type="text" value="{{WIFI_CFG_IP}}">
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="gwip">Gateway IP</label> <label for="gwip">Gateway IP</label>
<input id="gwip" name="gwip" type="text" value="{{WIFI_CFG_GW}}"> <input id="gwip" name="gwip" type="text" value="{{WIFI_CFG_GW}}">
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="ip">Netmask</label> <label for="ip">Netmask</label>
<input id="netmask" name="netmas" type="text" value="{{WIFI_CFG_NM}}"> <input id="netmask" name="netmas" type="text" value="{{WIFI_CFG_NM}}">
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="ip">DNS</label> <label for="ip">DNS</label>
<input id="netmask" name="dns" type="text" value="{{WIFI_CFG_DNS}}"> <input id="netmask" name="dns" type="text" value="{{WIFI_CFG_DNS}}">
</div> </div>
<div class="pure-controls"> <div class="pure-controls">
<button type="submit" class="pure-button pure-button-primary">Save</button> <button type="submit" class="pure-button pure-button-primary">Save</button>
</div> </div>
</form> </form>
</div><!-- end of config div --> </div><!-- end of config div -->

View file

@ -1,251 +1,254 @@
<!-- bottom --> <!-- bottom -->
<div id="tab-tde" class=""> <!-- timing editor --> <script>
<div id="tc-edit-container" class=""></div> var tabMain = document.getElementById("tab-lights");
</div> <!-- end of tab-tde --> var tabConfig = document.getElementById("tab-config");
<script> var tabTDE = document.getElementById("tab-tde");
function addTabListener() {
try { var amain = document.getElementById("tab-a-lights");
var tabMain = document.getElementById("tab-lights"); var acfg = document.getElementById("tab-a-config");
var tabConfig = document.getElementById("tab-config"); var atde = document.getElementById("tab-a-tde");
var tabTDE = document.getElementById("tab-tde");
var amain = document.getElementById("tab-a-lights");
var acfg = document.getElementById("tab-a-config"); document.getElementById("tab-a-lights").addEventListener("click", function() {
var atde = document.getElementById("tab-a-tde"); tabMain.classList.add("visible");
amain.addEventListener("click", function() { tabConfig.classList.remove("visible");
tabMain.classList.add("visible"); tabTDE.classList.remove("visible");
tabConfig.classList.remove("visible");
tabTDE.classList.remove("visible"); amain.classList.add("pure-button-primary");
amain.classList.add("pure-button-primary"); acfg.classList.remove("pure-button-primary");
acfg.classList.remove("pure-button-primary"); atde.classList.remove("pure-button-primary");
atde.classList.remove("pure-button-primary"); });
});
acfg.addEventListener("click", function() { document.getElementById("tab-a-config").addEventListener("click", function() {
tabMain.classList.remove("visible"); tabMain.classList.remove("visible");
tabConfig.classList.add("visible"); tabConfig.classList.add("visible");
tabTDE.classList.remove("visible"); tabTDE.classList.remove("visible");
amain.classList.remove("pure-button-primary");
acfg.classList.add("pure-button-primary"); amain.classList.remove("pure-button-primary");
atde.classList.remove("pure-button-primary"); acfg.classList.add("pure-button-primary");
}); atde.classList.remove("pure-button-primary");
atde.addEventListener("click", function() { });
tabMain.classList.remove("visible");
tabConfig.classList.remove("visible"); document.getElementById("tab-a-tde").addEventListener("click", function() {
tabTDE.classList.add("visible"); tabMain.classList.remove("visible");
amain.classList.remove("pure-button-primary"); tabConfig.classList.remove("visible");
acfg.classList.remove("pure-button-primary"); tabTDE.classList.add("visible");
atde.classList.add("pure-button-primary");
}); amain.classList.remove("pure-button-primary");
} catch (error) { acfg.classList.remove("pure-button-primary");
console.log("Fehler in load listener of the tab action listener management: " + error.message); atde.classList.add("pure-button-primary");
} });
}
window.addEventListener('load', function() { function loadGraphData() {
addTabListener(); console.log('----> generate graph <----');
}); $.getJSON('/tc_data_blocks', function(data) {
function loadGraphData() { var currenttime = [];
console.log('----> generate graph <----'); var time = [];
$.getJSON('/tc_data_blocks_read', function(data) { var channel1 = [];
var currenttime = []; var channel2 = [];
var time = []; var channel3 = [];
var channel1 = []; var channel4 = [];
var channel2 = []; for (var i = 0; i < data['tcdata'].length; i++) {
var channel3 = []; time.push(data['tcdata'][i]['hour'] + ':' + (data['tcdata'][i]['min'] < 10 ? '0' : '') + data['tcdata'][i]['min']);
var channel4 = []; channel1.push(data['tcdata'][i]['ch1']);
for (var i = 0; i < data['tcdata'].length; i++) { channel2.push(data['tcdata'][i]['ch2']);
time.push(data['tcdata'][i]['hour'] + ':' + (data['tcdata'][i]['min'] < 10 ? '0' : '') + data['tcdata'][i]['min']); channel3.push(data['tcdata'][i]['ch3']);
channel1.push(data['tcdata'][i]['ch1']); channel4.push(data['tcdata'][i]['ch4']);
channel2.push(data['tcdata'][i]['ch2']); }
channel3.push(data['tcdata'][i]['ch3']); currenttime.push(data['currenttime']['hour']);
channel4.push(data['tcdata'][i]['ch4']); currenttime.push(data['currenttime']['min']);
} console.log(currenttime);
currenttime.push(data['currenttime']['hour']); var currentTimeStr = currenttime[0] + ':' + (currenttime[1] < 10 ? '0' : '') + currenttime[1];
currenttime.push(data['currenttime']['min']); var index = time.indexOf(currentTimeStr);
console.log(currenttime); if (index === -1) {
var currentTimeStr = currenttime[0] + ':' + (currenttime[1] < 10 ? '0' : '') + currenttime[1]; var lowerIndex = -1;
var index = time.indexOf(currentTimeStr); var upperIndex = -1;
if (index === -1) { for (var i = 0; i < time.length - 1; i++) {
var lowerIndex = -1; console.log(time[i] + ' <= ' + currentTimeStr + ' >= ' + time[i + 1]);
var upperIndex = -1; const currentDate = new Date();
for (var i = 0; i < time.length - 1; i++) { const year = currentDate.getFullYear();
console.log(time[i] + ' <= ' + currentTimeStr + ' >= ' + time[i + 1]); const month = (currentDate.getMonth() + 1).toString().padStart(2, '0');
const currentDate = new Date(); const day = currentDate.getDate().toString().padStart(2, '0');
const year = currentDate.getFullYear(); const dateString = `${year}-${month}-${day}`;
const month = (currentDate.getMonth() + 1).toString().padStart(2, '0'); const start = moment(dateString + ' ' + time[i], 'YYYY-MM-DD HH:mm');
const day = currentDate.getDate().toString().padStart(2, '0'); const curr = moment(dateString + ' ' + currentTimeStr, 'YYYY-MM-DD HH:mm');
const dateString = `${year}-${month}-${day}`; const end = moment(dateString + ' ' + time[i + 1], 'YYYY-MM-DD HH:mm');
const start = moment(dateString + ' ' + time[i], 'YYYY-MM-DD HH:mm'); console.log(start.format('YYYY-MM-DD HH:mm') + ' <= ' + curr.format('YYYY-MM-DD HH:mm') + ' >= ' + end.format('YYYY-MM-DD HH:mm'));
const curr = moment(dateString + ' ' + currentTimeStr, 'YYYY-MM-DD HH:mm'); console.log(curr.isBetween(start, end));
const end = moment(dateString + ' ' + time[i + 1], 'YYYY-MM-DD HH:mm'); if (curr.isBetween(start, end)) {
console.log(start.format('YYYY-MM-DD HH:mm') + ' <= ' + curr.format('YYYY-MM-DD HH:mm') + ' >= ' + end.format('YYYY-MM-DD HH:mm')); lowerIndex = i;
console.log(curr.isBetween(start, end)); upperIndex = i + 1;
if (curr.isBetween(start, end)) { break;
lowerIndex = i; }
upperIndex = i + 1; }
break; console.log('lowerIndex=' + lowerIndex);
} console.log('upperIndex=' + upperIndex);
} if (lowerIndex === -1 || upperIndex === -1) {
console.log('lowerIndex=' + lowerIndex); console.log("Error: Current time not found in time array and not between two elements in time array.");
console.log('upperIndex=' + upperIndex); lowerIndex = 0;
if (lowerIndex === -1 || upperIndex === -1) { upperIndex = 1;
console.log("Error: Current time not found in time array and not between two elements in time array."); var tmp1 = time[0].split(':');
lowerIndex = 0; console.log('tmp1 = ' + tmp1);
upperIndex = 1; currenttime[0] = tmp1[0];
var tmp1 = time[0].split(':'); currenttime[1] = tmp1[1];
console.log('tmp1 = ' + tmp1); }
currenttime[0] = tmp1[0]; var lowerTime = time[lowerIndex].split(":");
currenttime[1] = tmp1[1]; var upperTime = time[upperIndex].split(":");
} var timeDiff = (currenttime[0] - lowerTime[0]) + ((currenttime[1] - lowerTime[1]) / 60);
var lowerTime = time[lowerIndex].split(":"); var indexFloat = lowerIndex + timeDiff / ((upperTime[0] - lowerTime[0]) + ((upperTime[1] - lowerTime[1]) / 60));
var upperTime = time[upperIndex].split(":"); console.log("Index (float): " + indexFloat);
var timeDiff = (currenttime[0] - lowerTime[0]) + ((currenttime[1] - lowerTime[1]) / 60); } else {
var indexFloat = lowerIndex + timeDiff / ((upperTime[0] - lowerTime[0]) + ((upperTime[1] - lowerTime[1]) / 60)); console.log("Index (integer): " + index);
console.log("Index (float): " + indexFloat); console.log("Index (float): " + index);
} else { }
console.log("Index (integer): " + index); if (indexFloat > index) {
console.log("Index (float): " + index); index = indexFloat;
} }
if (indexFloat > index) { console.log("index in graph >>>" + index);
index = indexFloat; var trace1 = {
} x: time,
console.log("index in graph >>>" + index); y: channel1,
var trace1 = { name: 'Channel 1',
x: time, type: 'scatter',
y: channel1, mode: 'lines+markers',
name: 'Channel 1', };
type: 'scatter', var trace2 = {
mode: 'lines+markers', x: time,
}; y: channel2,
var trace2 = { name: 'Channel 2',
x: time, type: 'scatter',
y: channel2, mode: 'lines+markers',
name: 'Channel 2', };
type: 'scatter', var trace3 = {
mode: 'lines+markers', x: time,
}; y: channel3,
var trace3 = { name: 'Channel 3',
x: time, type: 'scatter',
y: channel3, mode: 'lines+markers',
name: 'Channel 3', };
type: 'scatter', var trace4 = {
mode: 'lines+markers', x: time,
}; y: channel4,
var trace4 = { name: 'Channel 4',
x: time, type: 'scatter',
y: channel4, mode: 'lines+markers',
name: 'Channel 4', };
type: 'scatter', var layout = {
mode: 'lines+markers', title: 'Timing Control Data Blocks',
}; xaxis: {
var layout = { title: 'Time',
title: 'Timing Control Data Blocks', tickangle: -45,
xaxis: { },
title: 'Time', yaxis: {
tickangle: -45, title: 'Brightness',
}, range: [0, 255],
yaxis: { },
title: 'Brightness', shapes: [{
range: [0, 255], type: 'line',
}, x0: index,
shapes: [{ y0: 0,
type: 'line', x1: index,
x0: index, y1: 255,
y0: 0, line: {
x1: index, color: 'lightgrey',
y1: 255, width: 3,
line: { dash: 'dot'
color: 'lightgrey', }
width: 3, }]
dash: 'dot' };
} Plotly.newPlot('plot_chart', [trace1, trace2, trace3, trace4], layout);
}] });
}; }
Plotly.newPlot('plot_chart', [trace1, trace2, trace3, trace4], layout); setInterval(loadGraphData, 10000);
}); loadGraphData();
}
setInterval(loadGraphData, 10000); function updateLightState() {
loadGraphData(); console.log('----> setting bri and power switch <----');
function updateLightState() { for (let i = 1; i <= {{LIGHT_COUNT}}; i++) {
console.log('----> setting bri and power switch <----'); const lightURL = `http://{{IP_ADDRESS}}/state?light=${i}`;
for (let i = 1; i <= {{LIGHT_COUNT}}; i++) { fetch(lightURL).then(response => response.json()).then(data => {
const lightURL = `http://{{IP_ADDRESS}}/state?light=${i}`; const briSlider = document.getElementById(`bri${i - 1}`);
fetch(lightURL).then(response => response.json()).then(data => { const briSliderVal = document.getElementById(`bri${i - 1}_val`);
const briSlider = document.getElementById(`bri${i - 1}`); const onLinkOn = document.getElementById(`on${i - 1}_on`);
const briSliderVal = document.getElementById(`bri${i - 1}_val`); const onLinkOff = document.getElementById(`on${i - 1}_off`);
const onLinkOn = document.getElementById(`on${i - 1}_on`); briSlider.value = data.bri;
const onLinkOff = document.getElementById(`on${i - 1}_off`); briSliderVal.innerHTML = (Math.round((data.bri * 100.0 / 255.0) * 100) / 100).toFixed(2);
briSlider.value = data.bri; console.log('data.on ' + i + ' = ' + data.on);
briSliderVal.innerHTML = (Math.round((data.bri * 100.0 / 255.0) * 100) / 100).toFixed(2); if (data.on == true) {
console.log('data.on ' + i + ' = ' + data.on); onLinkOn.classList.add('pure-button-primary');
if (data.on == true) { onLinkOff.classList.remove('pure-button-primary');
onLinkOn.classList.add('pure-button-primary'); } else {
onLinkOff.classList.remove('pure-button-primary'); onLinkOn.classList.remove('pure-button-primary');
} else { onLinkOff.classList.add('pure-button-primary');
onLinkOn.classList.remove('pure-button-primary'); }
onLinkOff.classList.add('pure-button-primary'); }).catch(error => console.error(error));
} }
}).catch(error => console.error(error)); }
} setInterval(updateLightState, 10000);
} updateLightState();
setInterval(updateLightState, 10000);
updateLightState(); function updatePWMValues() {
function updatePWMValues() { console.log('----> setting pwm data <----');
console.log('----> setting pwm data <----'); for (let i = 0; i < {{LIGHT_COUNT}}; i++) {
for (let i = 0; i < {{LIGHT_COUNT}}; i++) { const lightID = i + 1;
const lightID = i + 1; const pwmElement = document.getElementById(`light${i}_pwm`);
const pwmElement = document.getElementById(`light${i}_pwm`); const pwmElementTxt = document.getElementById(`light${i}_pwm_txt`);
const pwmElementTxt = document.getElementById(`light${i}_pwm_txt`); if (pwmElement) {
if (pwmElement) { const url = `http://{{IP_ADDRESS}}/state?light=${lightID}`;
const url = `http://{{IP_ADDRESS}}/state?light=${lightID}`; fetch(url).then(response => response.json()).then(data => {
fetch(url).then(response => response.json()).then(data => { const pwmValue = ((Math.round((data.curpwm - ((data.curpwm >= {{PWM_MIN}}) ? {{PWM_MIN}} : 0)) / {{PWM_MAX}} * 10000) / 100).toFixed(2));
const pwmValue = ((Math.round((data.curpwm - ((data.curpwm >= {{PWM_MIN}}) ? {{PWM_MIN}} : 0)) / {{PWM_MAX}} * 10000) / 100).toFixed(2)); console.log('curpwm[' + i + '] = ' + data.curpwm + ' = ' + pwmValue);
console.log('curpwm[' + i + '] = ' + data.curpwm + ' = ' + pwmValue); pwmElement.innerText = pwmValue.toString();
pwmElement.innerText = pwmValue.toString(); pwmElement.value = pwmValue;
pwmElement.value = pwmValue; pwmElementTxt.innerText = pwmValue.toString();
pwmElementTxt.innerText = pwmValue.toString(); }).catch(error => console.error(error));
}).catch(error => console.error(error)); }
} }
} }
} updatePWMValues();
updatePWMValues(); setInterval(updatePWMValues, 5000);
setInterval(updatePWMValues, 5000);
var links = document.querySelectorAll('[id^="on"][id$="_off"]');
links.forEach(function(link) { var links = document.querySelectorAll('[id^="on"][id$="_off"]');
link.addEventListener('click', function(event) {
event.preventDefault(); links.forEach(function(link) {
var id = this.id.replace('on', '').replace('_off', ''); link.addEventListener('click', function(event) {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=false&transition=' + document.getElementById('transition').value, true); event.preventDefault();
xhr.send();
updateLightState(); var id = this.id.replace('on', '').replace('_off', '');
this.classList.add('pure-button-primary');
document.getElementById('on'+id+'_on').classList.remove('pure-button-primary'); var xhr = new XMLHttpRequest();
}); xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=false&transition=' + document.getElementById('transition').value, true);
});
var links = document.querySelectorAll('[id^="on"][id$="_on"]'); xhr.send();
links.forEach(function(link) { updateLightState();
link.addEventListener('click', function(event) { this.classList.add('pure-button-primary');
event.preventDefault(); document.getElementById('on'+id+'_on').classList.remove('pure-button-primary');
var id = this.id.replace('on', '').replace('_on', ''); });
var xhr = new XMLHttpRequest(); });
xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=true&transition=' + document.getElementById('transition').value, true);
xhr.send(); var links = document.querySelectorAll('[id^="on"][id$="_on"]');
updateLightState();
this.classList.add('pure-button-primary'); links.forEach(function(link) {
document.getElementById('on'+id+'_off').classList.remove('pure-button-primary'); link.addEventListener('click', function(event) {
});
}); event.preventDefault();
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://{{IP_ADDRESS}}/tc_data_edit'); var id = this.id.replace('on', '').replace('_on', '');
xhr.onload = function() {
if (xhr.status === 200) { var xhr = new XMLHttpRequest();
document.getElementById('tc-edit-container').innerHTML = xhr.responseText; xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=true&transition=' + document.getElementById('transition').value, true);
} else {
console.log('Fehler beim Laden der URL: ' + xhr.status); xhr.send();
} updateLightState();
}; this.classList.add('pure-button-primary');
xhr.send(); document.getElementById('on'+id+'_off').classList.remove('pure-button-primary');
</script> });
</div> });
</fieldset> </script>
</body>
</html> </div>
</fieldset>
</body>
</html>

View file

@ -1,8 +1,12 @@
<!-- middle --> <!-- middle -->
</td> </td>
<td> <td>
<div id="plot_chart"></div> <div id="plot_chart"></div>
</td> </td>
</tr> </tr>
</table> </table>
</div><!-- end of lights control tab --> </div><!-- end of lights control tab -->
<div id="tab-tde"> <!-- timing editor -->
Not implemented yet.
</div>

View file

@ -1,106 +1,108 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Light setup - {{LIGHT_NAME}}</title> <title>Light setup - {{LIGHT_NAME}}</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script> <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/purecss@0.6.2/build/pure-min.css"> <link rel="stylesheet" href="https://unpkg.com/purecss@0.6.2/build/pure-min.css">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<style> <style>
#tab-lights, #tab-config, #tab-tde { #tab-lights, #tab-config, #tab-tde {
display: none; display: none;
background-color: #ffffff; background-color: #ffffff;
color: black; color: black;
font-weight: bold; font-weight: bold;
} }
#tab-lights.visible { #tab-lights.visible {
display: block; display: block;
} }
#tab-config.visible { #tab-config.visible {
display: block; display: block;
} }
#tab-tde.visible { #tab-tde.visible {
display: block; display: block;
} }
</style> </style>
</head> </head>
<body> <body>
<fieldset> <fieldset>
<h3>{{LIGHT_NAME}}</h3> <h3>{{LIGHT_NAME}}</h3>
<div class="pure-form pure-form-aligned"> <div class="pure-form pure-form-aligned">
<div class="pure-controls"> <div class="pure-controls">
<a href="/update" class="pure-button">update</a> <a href="/update" class="pure-button">update</a>
<a href="/?reset=1" class="pure-button">reset light</a> <a href="/?reset=1" class="pure-button">reset light</a>
<a href="/?resettc" class="pure-button">reset timing control data</a> <a href="/?resettc" class="pure-button">reset timing control data</a>
<a href="/?alert=1" class="pure-button">alert</a> <a href="/?alert=1" class="pure-button">alert</a>
</div> </div>
<br> <br>
<div><!-- Tab links --> <div><!-- Tab links -->
<a href="#" id="tab-a-lights" class="pure-button pure-button-primary">Lights control</a> <a href="#" id="tab-a-lights" class="pure-button pure-button-primary">Lights control</a>
<a href="#" id="tab-a-config" class="pure-button">Config</a> <a href="#" id="tab-a-config" class="pure-button">Config</a>
<a href="#" id="tab-a-tde" class="pure-button">Timing data edit</a> <a href="#" id="tab-a-tde" class="pure-button">Timing data edit</a>
</div> </div>
<br> <br>
<div id="tab-lights" class="visible"> <!-- lights control tab --> <div id="tab-lights" class="visible"> <!-- lights control tab -->
<br> <br>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="tc_on"> <label for="tc_on">
<strong>Timing control</strong> <strong>Timing control</strong>
</label> </label>
<a id="tc_on" class="pure-button {{TC_LINK_PRIMARY_ON}}" href="#">ON</a> <a id="tc_on" class="pure-button {{TC_LINK_PRIMARY_ON}}" href="#">ON</a>
<a id="tc_off" class="pure-button {{TC_LINK_PRIMARY_OFF}}" href="#">OFF</a> <a id="tc_off" class="pure-button {{TC_LINK_PRIMARY_OFF}}" href="#">OFF</a>
<br> <br>
<label for="transition">Transition time (s)</label> <label for="transition">Transition time (s)</label>
<input id="transition" name="transition" type="text" placeholder="10" value="{{TRANSITION_TIME}}"> <input id="transition" name="transition" type="text" placeholder="10" value="{{TRANSITION_TIME}}">
</div> </div>
<br> <br>
<script> <script>
var links = document.querySelectorAll('[id^="tc_on"]'); var links = document.querySelectorAll('[id^="tc_on"]');
links.forEach(function(link) { links.forEach(function(link) {
link.addEventListener('click', function(event) { link.addEventListener('click', function(event) {
event.preventDefault(); event.preventDefault();
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://{{IP_ADDRESS}}/?tc=true', true); xhr.open('GET', 'http://{{IP_ADDRESS}}/?tc=true', true);
xhr.send(); xhr.send();
console.log('tc=true call'); console.log('tc=true call');
document.getElementById('tc_on').classList.add('pure-button-primary'); document.getElementById('tc_on').classList.add('pure-button-primary');
document.getElementById('tc_off').classList.remove('pure-button-primary'); document.getElementById('tc_off').classList.remove('pure-button-primary');
}); });
}); });
var links = document.querySelectorAll('[id^="tc_off"]'); var links = document.querySelectorAll('[id^="tc_off"]');
links.forEach(function(link) { links.forEach(function(link) {
link.addEventListener('click', function(event) { link.addEventListener('click', function(event) {
event.preventDefault(); event.preventDefault();
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://{{IP_ADDRESS}}/?tc=false', true); xhr.open('GET', 'http://{{IP_ADDRESS}}/?tc=false', true);
xhr.send(); xhr.send();
console.log('tc=false call'); console.log('tc=false call');
document.getElementById('tc_off').classList.add('pure-button-primary'); document.getElementById('tc_off').classList.add('pure-button-primary');
document.getElementById('tc_on').classList.remove('pure-button-primary'); document.getElementById('tc_on').classList.remove('pure-button-primary');
}); });
}); });
let timeoutId;
function sendSliderValue(x) { let timeoutId;
x = x - 1; function sendSliderValue(x) {
clearTimeout(timeoutId); x = x - 1;
timeoutId = setTimeout(() => { clearTimeout(timeoutId);
var value = document.getElementById(`bri${x}`).value; timeoutId = setTimeout(() => {
var url = `http://{{IP_ADDRESS}}/?bri${x}=${value}`; var value = document.getElementById(`bri${x}`).value;
fetch(url).then(response => { var url = `http://{{IP_ADDRESS}}/?bri${x}=${value}`;
if (!response.ok) { fetch(url).then(response => {
throw new Error(`HTTP error! status: ${response.status}`); if (!response.ok) {
} throw new Error(`HTTP error! status: ${response.status}`);
console.log(`Sent slider value ${value} to ${url}`); }
}).catch(error => { console.log(`Sent slider value ${value} to ${url}`);
console.error(`Error sending slider value to ${url}: ${error}`); }).catch(error => {
}); console.error(`Error sending slider value to ${url}: ${error}`);
}, 500); });
} }, 500);
</script> }
<br> </script>
<table border=0> <br>
<tr> <table border=0>
<td> <tr>
<td>

View file

@ -1,29 +1,29 @@
<h4>Light {{LIGHT_NUMBER}}</h4> <h4>Light {{LIGHT_NUMBER}}</h4>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="power"> <label for="power">
<strong>Power</strong> <strong>Power</strong>
</label> </label>
<a id="on{{LIGHT_NUMBER_DEC}}_on" class="pure-button" href="#">ON</a> <a id="on{{LIGHT_NUMBER_DEC}}_on" class="pure-button" href="#">ON</a>
<a id="on{{LIGHT_NUMBER_DEC}}_off" class="pure-button" href="#">OFF</a> <a id="on{{LIGHT_NUMBER_DEC}}_off" class="pure-button" href="#">OFF</a>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="bri{{LIGHT_NUMBER_DEC}}">Bri</label> <label for="bri{{LIGHT_NUMBER_DEC}}">Bri</label>
<input id="bri{{LIGHT_NUMBER_DEC}}" onchange="sendSliderValue({{LIGHT_NUMBER}})" name="bri{{LIGHT_NUMBER_DEC}}" type="range" min="0" max="255" value="25"> <input id="bri{{LIGHT_NUMBER_DEC}}" onchange="sendSliderValue({{LIGHT_NUMBER}})" name="bri{{LIGHT_NUMBER_DEC}}" type="range" min="0" max="255" value="25">
&nbsp; &nbsp;
<span id="bri{{LIGHT_NUMBER_DEC}}_val" name="bri{{LIGHT_NUMBER_DEC}}">9</span> <span id="bri{{LIGHT_NUMBER_DEC}}_val" name="bri{{LIGHT_NUMBER_DEC}}">9</span>
% %
<br> <br>
<label for="light{{LIGHT_NUMBER_DEC}}_pwm">PWM-Value</label> <label for="light{{LIGHT_NUMBER_DEC}}_pwm">PWM-Value</label>
<input type="range" min="0" max="100" value="0" id="light{{LIGHT_NUMBER_DEC}}_pwm" disabled> <input type="range" min="0" max="100" value="0" id="light{{LIGHT_NUMBER_DEC}}_pwm" disabled>
&nbsp; &nbsp;
<span id="light{{LIGHT_NUMBER_DEC}}_pwm_txt"></span> <span id="light{{LIGHT_NUMBER_DEC}}_pwm_txt"></span>
% %
<script> <script>
var slider{{LIGHT_NUMBER_DEC}} = document.getElementById("bri{{LIGHT_NUMBER_DEC}}"); var slider{{LIGHT_NUMBER_DEC}} = document.getElementById("bri{{LIGHT_NUMBER_DEC}}");
var output{{LIGHT_NUMBER_DEC}} = document.getElementById("bri{{LIGHT_NUMBER_DEC}}_val"); var output{{LIGHT_NUMBER_DEC}} = document.getElementById("bri{{LIGHT_NUMBER_DEC}}_val");
output{{LIGHT_NUMBER_DEC}}.innerHTML = (Math.round((slider{{LIGHT_NUMBER_DEC}}.value * 100.0 / 255.0) * 100) / 100).toFixed(2); output{{LIGHT_NUMBER_DEC}}.innerHTML = (Math.round((slider{{LIGHT_NUMBER_DEC}}.value * 100.0 / 255.0) * 100) / 100).toFixed(2);
slider{{LIGHT_NUMBER_DEC}}.oninput = function() { slider{{LIGHT_NUMBER_DEC}}.oninput = function() {
output{{LIGHT_NUMBER_DEC}}.innerHTML = (Math.round((this.value * 100.0 / 255.0) * 100) / 100).toFixed(2); output{{LIGHT_NUMBER_DEC}}.innerHTML = (Math.round((this.value * 100.0 / 255.0) * 100) / 100).toFixed(2);
} }
</script> </script>
</div> </div>

View file

@ -1,184 +0,0 @@
<br>
<div id="tc-edit-plotly-graph"></div>
<a href="#" onclick="sendTCData()" class="pure-button">Daten senden</a>
<script>
var dataPoints = [];
for (var i = 0; i < 10; i++) {
var xValue = i * 2;
dataPoints.push({ x: xValue, y: [0, 0, 0, 0] });
}
var options = {
title: {
text: "Graph Title"
},
data: [{
type: "line",
dataPoints: dataPoints
}]
};
var inputIdPrefixes = ["hour", "minute", "ch1", "ch2", "ch3", "ch4"];
var inputData = {
hour: [],
minute: [],
ch1: [],
ch2: [],
ch3: [],
ch4: []
};
var trace1 = {
x: [],
y: [],
mode: 'lines',
name: 'ch1'
};
var trace2 = {
x: [],
y: [],
mode: 'lines',
name: 'ch2'
};
var trace3 = {
x: [],
y: [],
mode: 'lines',
name: 'ch3'
};
var trace4 = {
x: [],
y: [],
mode: 'lines',
name: 'ch4'
};
var data = [trace1, trace2, trace3, trace4];
var layout = {
xaxis: {
title: 'Uhrzeit'
},
yaxis: {
title: 'Wert'
},
margin: {
l: 50,
r: 50,
b: 50,
t: 50,
pad: 4
},
hovermode: 'closest'
};
Plotly.newPlot('tc-edit-plotly-graph', data, layout);
var layout = {
title: 'Werte der Kanäle ch1 - ch4',
xaxis: {
title: 'Uhrzeit',
range: ['00:00', '23:59'],
tickformat: '%H:%M'
},
yaxis: {
title: 'Wert in %',
range: [0, 100]
}
};
var plotDiv = document.getElementById('plot');
Plotly.newPlot(plotDiv, [], layout, {responsive: true});
var data = [ { x: ['00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00'],
y: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
name: 'Channel 1',
mode: 'lines+markers',
line: {
shape: 'spline'
}
},
{
x: ['00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00'],
y: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
name: 'Channel 2',
mode: 'lines+markers',
line: {
shape: 'spline'
}
},
{
x: ['00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00'],
y: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
name: 'Channel 3',
mode: 'lines+markers',
line: {
shape: 'spline'
}
},
{
x: ['00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00'],
y: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
name: 'Channel 4',
mode: 'lines+markers',
line: {
shape: 'spline'
}
}
];
var layout = {
xaxis: {
title: 'Time (hh:mm)',
showgrid: false,
zeroline: false
},
yaxis: {
title: 'Value (%)',
showline: false
}
};
Plotly.newPlot('graph', data, layout);
var layout = {
title: 'Graph',
xaxis: {
title: 'Uhrzeit'
},
yaxis: {
title: 'Prozent'
},
hovermode: 'closest'
};
var plot_data = [{ x: [],
y: [],
mode: 'lines+markers',
line: { shape: 'spline' }
}];
Plotly.newPlot('graph', plot_data, layout);
function updateData() {
for (let i = 0; i < 10; i++) {
let hour = document.getElementById(`hour-${i}`).value;
let minute = document.getElementById(`minute-${i}`).value;
for (let j = 1; j <= 4; j++) {
let value = parseFloat(document.getElementById(`ch${j}-${i}`).value);
let index = i * 4 + (j - 1);
data[index].x = `${hour}:${minute}`;
data[index].y = value;
}
}
Plotly.update('graph', data, layout);
}
for (let i = 0; i < 10; i++) {
document.getElementById(`hour-${i}`).addEventListener('input', updateData);
document.getElementById(`minute-${i}`).addEventListener('input', updateData);
for (let j = 1; j <= 4; j++) {
document.getElementById(`ch${j}-${i}`).addEventListener('input', updateData);
}
}
function sendTCData() {
var data = [];
for (var i = 0; i < 10; i++) {
var hh = document.getElementById("hh_" + i).value;
var mm = document.getElementById("mm_" + i).value;
var ch1 = document.getElementById("ch1_" + i).value;
var ch2 = document.getElementById("ch2_" + i).value;
var ch3 = document.getElementById("ch3_" + i).value;
var ch4 = document.getElementById("ch4_" + i).value;
data.push({ "hh": hh, "mm": mm, "ch1": ch1, "ch2": ch2, "ch3": ch3, "ch4": ch4 });
}
var jsonData = encodeURIComponent(JSON.stringify(data));
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://{{IP_ADDRESS}}}}/tc_data_block_store?data=" + jsonData);
xhr.send();
}
</script>

View file

@ -472,28 +472,13 @@ void init_webserver()
server.send(200, "text/plain", output); server.send(200, "text/plain", output);
}); });
server.on("/tc_data_blocks_read", []() server.on("/tc_data_blocks", []()
{ {
String output = tc_getJsonData(); String output = tc_getJsonData();
server.send(200, "application/json", output); server.send(200, "application/json", output);
}); });
server.on("/tc_data_blocks_store", []()
{
if (server.hasArg("data"))
{
String jsonData = server.arg("data");
tc_jsonDataBlocksToEEPROM(jsonData);
server.send(200, "text/html", "tcdata saved");
}
});
server.on("/tc_data_edit", []()
{
server.send(200, "text/html", genTCEditHTML());
});
server.on("/", []() server.on("/", []()
{ {
@ -718,11 +703,6 @@ String genConfigHTML()
return replacePlaceholder(getConfigHTML()); return replacePlaceholder(getConfigHTML());
} }
String genTCEditHTML()
{
return replacePlaceholder(getTCDataEditHTML());
}
String genLightControlHTML() String genLightControlHTML()
{ {
String http_content = ""; String http_content = "";
@ -888,14 +868,6 @@ String getConfigHTML()
//********************************// //********************************//
String getTCDataEditHTML()
{
// load file
return loadSPIFFSFile("/tc_data_edit.html");
}
//********************************//
String getLightControlHTML() String getLightControlHTML()
{ {
// load file // load file

View file

@ -1,286 +1,254 @@
<!-- bottom --> <!-- bottom -->
<div id="tab-tde" class=""> <!-- timing editor --> <script>
<div id="tc-edit-container" class=""></div> var tabMain = document.getElementById("tab-lights");
</div> <!-- end of tab-tde --> var tabConfig = document.getElementById("tab-config");
var tabTDE = document.getElementById("tab-tde");
<script>
function addTabListener() { var amain = document.getElementById("tab-a-lights");
try { var acfg = document.getElementById("tab-a-config");
var tabMain = document.getElementById("tab-lights"); var atde = document.getElementById("tab-a-tde");
var tabConfig = document.getElementById("tab-config");
var tabTDE = document.getElementById("tab-tde");
document.getElementById("tab-a-lights").addEventListener("click", function() {
var amain = document.getElementById("tab-a-lights"); tabMain.classList.add("visible");
var acfg = document.getElementById("tab-a-config"); tabConfig.classList.remove("visible");
var atde = document.getElementById("tab-a-tde"); tabTDE.classList.remove("visible");
amain.classList.add("pure-button-primary");
amain.addEventListener("click", function() { acfg.classList.remove("pure-button-primary");
tabMain.classList.add("visible"); atde.classList.remove("pure-button-primary");
tabConfig.classList.remove("visible"); });
tabTDE.classList.remove("visible");
document.getElementById("tab-a-config").addEventListener("click", function() {
amain.classList.add("pure-button-primary"); tabMain.classList.remove("visible");
acfg.classList.remove("pure-button-primary"); tabConfig.classList.add("visible");
atde.classList.remove("pure-button-primary"); tabTDE.classList.remove("visible");
});
amain.classList.remove("pure-button-primary");
acfg.addEventListener("click", function() { acfg.classList.add("pure-button-primary");
tabMain.classList.remove("visible"); atde.classList.remove("pure-button-primary");
tabConfig.classList.add("visible"); });
tabTDE.classList.remove("visible");
document.getElementById("tab-a-tde").addEventListener("click", function() {
amain.classList.remove("pure-button-primary"); tabMain.classList.remove("visible");
acfg.classList.add("pure-button-primary"); tabConfig.classList.remove("visible");
atde.classList.remove("pure-button-primary"); tabTDE.classList.add("visible");
});
amain.classList.remove("pure-button-primary");
atde.addEventListener("click", function() { acfg.classList.remove("pure-button-primary");
tabMain.classList.remove("visible"); atde.classList.add("pure-button-primary");
tabConfig.classList.remove("visible"); });
tabTDE.classList.add("visible");
function loadGraphData() {
amain.classList.remove("pure-button-primary"); console.log('----> generate graph <----');
acfg.classList.remove("pure-button-primary"); $.getJSON('/tc_data_blocks', function(data) {
atde.classList.add("pure-button-primary"); var currenttime = [];
}); var time = [];
} catch (error) { var channel1 = [];
console.log("Fehler in load listener of the tab action listener management: " + error.message); var channel2 = [];
} var channel3 = [];
} var channel4 = [];
window.addEventListener('load', function() { for (var i = 0; i < data['tcdata'].length; i++) {
addTabListener(); time.push(data['tcdata'][i]['hour'] + ':' + (data['tcdata'][i]['min'] < 10 ? '0' : '') + data['tcdata'][i]['min']);
}); channel1.push(data['tcdata'][i]['ch1']);
channel2.push(data['tcdata'][i]['ch2']);
function loadGraphData() { channel3.push(data['tcdata'][i]['ch3']);
console.log('----> generate graph <----'); channel4.push(data['tcdata'][i]['ch4']);
$.getJSON('/tc_data_blocks_read', function(data) { }
var currenttime = []; currenttime.push(data['currenttime']['hour']);
var time = []; currenttime.push(data['currenttime']['min']);
var channel1 = []; console.log(currenttime);
var channel2 = []; var currentTimeStr = currenttime[0] + ':' + (currenttime[1] < 10 ? '0' : '') + currenttime[1];
var channel3 = []; var index = time.indexOf(currentTimeStr);
var channel4 = []; if (index === -1) {
for (var i = 0; i < data['tcdata'].length; i++) { var lowerIndex = -1;
time.push(data['tcdata'][i]['hour'] + ':' + (data['tcdata'][i]['min'] < 10 ? '0' : '') + data['tcdata'][i]['min']); var upperIndex = -1;
channel1.push(data['tcdata'][i]['ch1']); for (var i = 0; i < time.length - 1; i++) {
channel2.push(data['tcdata'][i]['ch2']); console.log(time[i] + ' <= ' + currentTimeStr + ' >= ' + time[i + 1]);
channel3.push(data['tcdata'][i]['ch3']); const currentDate = new Date();
channel4.push(data['tcdata'][i]['ch4']); const year = currentDate.getFullYear();
} const month = (currentDate.getMonth() + 1).toString().padStart(2, '0');
currenttime.push(data['currenttime']['hour']); const day = currentDate.getDate().toString().padStart(2, '0');
currenttime.push(data['currenttime']['min']); const dateString = `${year}-${month}-${day}`;
console.log(currenttime); const start = moment(dateString + ' ' + time[i], 'YYYY-MM-DD HH:mm');
var currentTimeStr = currenttime[0] + ':' + (currenttime[1] < 10 ? '0' : '') + currenttime[1]; const curr = moment(dateString + ' ' + currentTimeStr, 'YYYY-MM-DD HH:mm');
var index = time.indexOf(currentTimeStr); const end = moment(dateString + ' ' + time[i + 1], 'YYYY-MM-DD HH:mm');
if (index === -1) { console.log(start.format('YYYY-MM-DD HH:mm') + ' <= ' + curr.format('YYYY-MM-DD HH:mm') + ' >= ' + end.format('YYYY-MM-DD HH:mm'));
var lowerIndex = -1; console.log(curr.isBetween(start, end));
var upperIndex = -1; if (curr.isBetween(start, end)) {
for (var i = 0; i < time.length - 1; i++) { lowerIndex = i;
console.log(time[i] + ' <= ' + currentTimeStr + ' >= ' + time[i + 1]); upperIndex = i + 1;
const currentDate = new Date(); break;
const year = currentDate.getFullYear(); }
const month = (currentDate.getMonth() + 1).toString().padStart(2, '0'); }
const day = currentDate.getDate().toString().padStart(2, '0'); console.log('lowerIndex=' + lowerIndex);
const dateString = `${year}-${month}-${day}`; console.log('upperIndex=' + upperIndex);
const start = moment(dateString + ' ' + time[i], 'YYYY-MM-DD HH:mm'); if (lowerIndex === -1 || upperIndex === -1) {
const curr = moment(dateString + ' ' + currentTimeStr, 'YYYY-MM-DD HH:mm'); console.log("Error: Current time not found in time array and not between two elements in time array.");
const end = moment(dateString + ' ' + time[i + 1], 'YYYY-MM-DD HH:mm'); lowerIndex = 0;
console.log(start.format('YYYY-MM-DD HH:mm') + ' <= ' + curr.format('YYYY-MM-DD HH:mm') + ' >= ' + end.format('YYYY-MM-DD HH:mm')); upperIndex = 1;
console.log(curr.isBetween(start, end)); var tmp1 = time[0].split(':');
if (curr.isBetween(start, end)) { console.log('tmp1 = ' + tmp1);
lowerIndex = i; currenttime[0] = tmp1[0];
upperIndex = i + 1; currenttime[1] = tmp1[1];
break; }
} var lowerTime = time[lowerIndex].split(":");
} var upperTime = time[upperIndex].split(":");
console.log('lowerIndex=' + lowerIndex); var timeDiff = (currenttime[0] - lowerTime[0]) + ((currenttime[1] - lowerTime[1]) / 60);
console.log('upperIndex=' + upperIndex); var indexFloat = lowerIndex + timeDiff / ((upperTime[0] - lowerTime[0]) + ((upperTime[1] - lowerTime[1]) / 60));
if (lowerIndex === -1 || upperIndex === -1) { console.log("Index (float): " + indexFloat);
console.log("Error: Current time not found in time array and not between two elements in time array."); } else {
lowerIndex = 0; console.log("Index (integer): " + index);
upperIndex = 1; console.log("Index (float): " + index);
var tmp1 = time[0].split(':'); }
console.log('tmp1 = ' + tmp1); if (indexFloat > index) {
currenttime[0] = tmp1[0]; index = indexFloat;
currenttime[1] = tmp1[1]; }
} console.log("index in graph >>>" + index);
var lowerTime = time[lowerIndex].split(":"); var trace1 = {
var upperTime = time[upperIndex].split(":"); x: time,
var timeDiff = (currenttime[0] - lowerTime[0]) + ((currenttime[1] - lowerTime[1]) / 60); y: channel1,
var indexFloat = lowerIndex + timeDiff / ((upperTime[0] - lowerTime[0]) + ((upperTime[1] - lowerTime[1]) / 60)); name: 'Channel 1',
console.log("Index (float): " + indexFloat); type: 'scatter',
} else { mode: 'lines+markers',
console.log("Index (integer): " + index); };
console.log("Index (float): " + index); var trace2 = {
} x: time,
if (indexFloat > index) { y: channel2,
index = indexFloat; name: 'Channel 2',
} type: 'scatter',
console.log("index in graph >>>" + index); mode: 'lines+markers',
var trace1 = { };
x: time, var trace3 = {
y: channel1, x: time,
name: 'Channel 1', y: channel3,
type: 'scatter', name: 'Channel 3',
mode: 'lines+markers', type: 'scatter',
}; mode: 'lines+markers',
var trace2 = { };
x: time, var trace4 = {
y: channel2, x: time,
name: 'Channel 2', y: channel4,
type: 'scatter', name: 'Channel 4',
mode: 'lines+markers', type: 'scatter',
}; mode: 'lines+markers',
var trace3 = { };
x: time, var layout = {
y: channel3, title: 'Timing Control Data Blocks',
name: 'Channel 3', xaxis: {
type: 'scatter', title: 'Time',
mode: 'lines+markers', tickangle: -45,
}; },
var trace4 = { yaxis: {
x: time, title: 'Brightness',
y: channel4, range: [0, 255],
name: 'Channel 4', },
type: 'scatter', shapes: [{
mode: 'lines+markers', type: 'line',
}; x0: index,
var layout = { y0: 0,
title: 'Timing Control Data Blocks', x1: index,
xaxis: { y1: 255,
title: 'Time', line: {
tickangle: -45, color: 'lightgrey',
}, width: 3,
yaxis: { dash: 'dot'
title: 'Brightness', }
range: [0, 255], }]
}, };
shapes: [{ Plotly.newPlot('plot_chart', [trace1, trace2, trace3, trace4], layout);
type: 'line', });
x0: index, }
y0: 0, setInterval(loadGraphData, 10000);
x1: index, loadGraphData();
y1: 255,
line: { function updateLightState() {
color: 'lightgrey', console.log('----> setting bri and power switch <----');
width: 3, for (let i = 1; i <= {{LIGHT_COUNT}}; i++) {
dash: 'dot' const lightURL = `http://{{IP_ADDRESS}}/state?light=${i}`;
} fetch(lightURL).then(response => response.json()).then(data => {
}] const briSlider = document.getElementById(`bri${i - 1}`);
}; const briSliderVal = document.getElementById(`bri${i - 1}_val`);
Plotly.newPlot('plot_chart', [trace1, trace2, trace3, trace4], layout); const onLinkOn = document.getElementById(`on${i - 1}_on`);
}); const onLinkOff = document.getElementById(`on${i - 1}_off`);
} briSlider.value = data.bri;
setInterval(loadGraphData, 10000); briSliderVal.innerHTML = (Math.round((data.bri * 100.0 / 255.0) * 100) / 100).toFixed(2);
loadGraphData(); console.log('data.on ' + i + ' = ' + data.on);
if (data.on == true) {
function updateLightState() { onLinkOn.classList.add('pure-button-primary');
console.log('----> setting bri and power switch <----'); onLinkOff.classList.remove('pure-button-primary');
for (let i = 1; i <= {{LIGHT_COUNT}}; i++) { } else {
const lightURL = `http://{{IP_ADDRESS}}/state?light=${i}`; onLinkOn.classList.remove('pure-button-primary');
fetch(lightURL).then(response => response.json()).then(data => { onLinkOff.classList.add('pure-button-primary');
const briSlider = document.getElementById(`bri${i - 1}`); }
const briSliderVal = document.getElementById(`bri${i - 1}_val`); }).catch(error => console.error(error));
const onLinkOn = document.getElementById(`on${i - 1}_on`); }
const onLinkOff = document.getElementById(`on${i - 1}_off`); }
briSlider.value = data.bri; setInterval(updateLightState, 10000);
briSliderVal.innerHTML = (Math.round((data.bri * 100.0 / 255.0) * 100) / 100).toFixed(2); updateLightState();
console.log('data.on ' + i + ' = ' + data.on);
if (data.on == true) { function updatePWMValues() {
onLinkOn.classList.add('pure-button-primary'); console.log('----> setting pwm data <----');
onLinkOff.classList.remove('pure-button-primary'); for (let i = 0; i < {{LIGHT_COUNT}}; i++) {
} else { const lightID = i + 1;
onLinkOn.classList.remove('pure-button-primary'); const pwmElement = document.getElementById(`light${i}_pwm`);
onLinkOff.classList.add('pure-button-primary'); const pwmElementTxt = document.getElementById(`light${i}_pwm_txt`);
} if (pwmElement) {
}).catch(error => console.error(error)); const url = `http://{{IP_ADDRESS}}/state?light=${lightID}`;
} fetch(url).then(response => response.json()).then(data => {
} const pwmValue = ((Math.round((data.curpwm - ((data.curpwm >= {{PWM_MIN}}) ? {{PWM_MIN}} : 0)) / {{PWM_MAX}} * 10000) / 100).toFixed(2));
setInterval(updateLightState, 10000); console.log('curpwm[' + i + '] = ' + data.curpwm + ' = ' + pwmValue);
updateLightState(); pwmElement.innerText = pwmValue.toString();
pwmElement.value = pwmValue;
function updatePWMValues() { pwmElementTxt.innerText = pwmValue.toString();
console.log('----> setting pwm data <----'); }).catch(error => console.error(error));
for (let i = 0; i < {{LIGHT_COUNT}}; i++) { }
const lightID = i + 1; }
const pwmElement = document.getElementById(`light${i}_pwm`); }
const pwmElementTxt = document.getElementById(`light${i}_pwm_txt`); updatePWMValues();
if (pwmElement) { setInterval(updatePWMValues, 5000);
const url = `http://{{IP_ADDRESS}}/state?light=${lightID}`;
fetch(url).then(response => response.json()).then(data => { // Suche nach allen Links auf der Seite mit IDs von on0_off bis on3_off
const pwmValue = ((Math.round((data.curpwm - ((data.curpwm >= {{PWM_MIN}}) ? {{PWM_MIN}} : 0)) / {{PWM_MAX}} * 10000) / 100).toFixed(2)); var links = document.querySelectorAll('[id^="on"][id$="_off"]');
console.log('curpwm[' + i + '] = ' + data.curpwm + ' = ' + pwmValue); // Füge einen Klick-Listener zu jedem Link hinzu
pwmElement.innerText = pwmValue.toString(); links.forEach(function(link) {
pwmElement.value = pwmValue; link.addEventListener('click', function(event) {
pwmElementTxt.innerText = pwmValue.toString(); // Verhindere, dass der Link die Seite neu lädt
}).catch(error => console.error(error)); event.preventDefault();
} // Extrahiere die Zahl aus der ID des Links
} var id = this.id.replace('on', '').replace('_off', '');
} // Erstelle eine neue Anfrage an die entsprechende URL
updatePWMValues(); var xhr = new XMLHttpRequest();
setInterval(updatePWMValues, 5000); xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=false&transition=' + document.getElementById('transition').value, true);
// Sende die Anfrage im Hintergrund
// Suche nach allen Links auf der Seite mit IDs von on0_off bis on3_off xhr.send();
var links = document.querySelectorAll('[id^="on"][id$="_off"]'); updateLightState();
// Füge einen Klick-Listener zu jedem Link hinzu this.classList.add('pure-button-primary');
links.forEach(function(link) { document.getElementById('on'+id+'_on').classList.remove('pure-button-primary');
link.addEventListener('click', function(event) { });
// Verhindere, dass der Link die Seite neu lädt });
event.preventDefault(); // Suche nach allen Links auf der Seite mit IDs von on0_off bis on3_off
// Extrahiere die Zahl aus der ID des Links var links = document.querySelectorAll('[id^="on"][id$="_on"]');
var id = this.id.replace('on', '').replace('_off', ''); // Füge einen Klick-Listener zu jedem Link hinzu
// Erstelle eine neue Anfrage an die entsprechende URL links.forEach(function(link) {
var xhr = new XMLHttpRequest(); link.addEventListener('click', function(event) {
xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=false&transition=' + document.getElementById('transition').value, true); // Verhindere, dass der Link die Seite neu lädt
// Sende die Anfrage im Hintergrund event.preventDefault();
xhr.send(); // Extrahiere die Zahl aus der ID des Links
updateLightState(); var id = this.id.replace('on', '').replace('_on', '');
this.classList.add('pure-button-primary'); // Erstelle eine neue Anfrage an die entsprechende URL
document.getElementById('on'+id+'_on').classList.remove('pure-button-primary'); var xhr = new XMLHttpRequest();
}); xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=true&transition=' + document.getElementById('transition').value, true);
}); // Sende die Anfrage im Hintergrund
// Suche nach allen Links auf der Seite mit IDs von on0_off bis on3_off xhr.send();
var links = document.querySelectorAll('[id^="on"][id$="_on"]'); updateLightState();
// Füge einen Klick-Listener zu jedem Link hinzu this.classList.add('pure-button-primary');
links.forEach(function(link) { document.getElementById('on'+id+'_off').classList.remove('pure-button-primary');
link.addEventListener('click', function(event) { });
// Verhindere, dass der Link die Seite neu lädt });
event.preventDefault(); </script>
// Extrahiere die Zahl aus der ID des Links
var id = this.id.replace('on', '').replace('_on', ''); </div>
// Erstelle eine neue Anfrage an die entsprechende URL </fieldset>
var xhr = new XMLHttpRequest(); </body>
xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=true&transition=' + document.getElementById('transition').value, true); </html>
// Sende die Anfrage im Hintergrund
xhr.send();
updateLightState();
this.classList.add('pure-button-primary');
document.getElementById('on'+id+'_off').classList.remove('pure-button-primary');
});
});
// Erstellen einer neuen XMLHttpRequest-Instanz
var xhr = new XMLHttpRequest();
// Angeben der URL und des HTTP-Request-Typs
xhr.open('GET', 'http://{{IP_ADDRESS}}/tc_data_edit');
// Festlegen der Funktion, die aufgerufen wird, wenn die Anfrage abgeschlossen ist
xhr.onload = function() {
// Überprüfen, ob die Anfrage erfolgreich war
if (xhr.status === 200) {
// Fügen Sie den empfangenen HTML-Code in den Container ein
document.getElementById('tc-edit-container').innerHTML = xhr.responseText;
} else {
// Wenn die Anfrage fehlgeschlagen ist, geben Sie einen Fehler aus
console.log('Fehler beim Laden der URL: ' + xhr.status);
}
};
// Senden der Anfrage
xhr.send();
</script>
</div>
</fieldset>
</body>
</html>

View file

@ -1,8 +1,12 @@
<!-- middle --> <!-- middle -->
</td> </td>
<td> <td>
<div id="plot_chart"></div> <div id="plot_chart"></div>
</td> </td>
</tr> </tr>
</table> </table>
</div><!-- end of lights control tab --> </div><!-- end of lights control tab -->
<div id="tab-tde"> <!-- timing editor -->
Not implemented yet.
</div>

View file

@ -1,227 +0,0 @@
<br>
<div id="tc-edit-plotly-graph"></div>
<a href="#" onclick="sendTCData()" class="pure-button">Daten senden</a>
<script>
// Variablen für die Datenpunkte des Graphen
var dataPoints = [];
for (var i = 0; i < 10; i++) {
var xValue = i * 2;
dataPoints.push({ x: xValue, y: [0, 0, 0, 0] });
}
// Optionen für den Graphen
var options = {
title: {
text: "Graph Title"
},
data: [{
type: "line",
dataPoints: dataPoints
}]
};
// ID-Präfixe für die Eingabefelder
var inputIdPrefixes = ["hour", "minute", "ch1", "ch2", "ch3", "ch4"];
// Aktuelle Eingabefeld-Daten
var inputData = {
hour: [],
minute: [],
ch1: [],
ch2: [],
ch3: [],
ch4: []
};
// initialisiere Graph
var trace1 = {
x: [], // Uhrzeit
y: [], // Wert für ch1
mode: 'lines',
name: 'ch1'
};
var trace2 = {
x: [], // Uhrzeit
y: [], // Wert für ch2
mode: 'lines',
name: 'ch2'
};
var trace3 = {
x: [], // Uhrzeit
y: [], // Wert für ch3
mode: 'lines',
name: 'ch3'
};
var trace4 = {
x: [], // Uhrzeit
y: [], // Wert für ch4
mode: 'lines',
name: 'ch4'
};
var data = [trace1, trace2, trace3, trace4];
var layout = {
xaxis: {
title: 'Uhrzeit'
},
yaxis: {
title: 'Wert'
},
margin: {
l: 50,
r: 50,
b: 50,
t: 50,
pad: 4
},
hovermode: 'closest'
};
Plotly.newPlot('tc-edit-plotly-graph', data, layout);
// initialisiere Graph
var layout = {
title: 'Werte der Kanäle ch1 - ch4',
xaxis: {
title: 'Uhrzeit',
range: ['00:00', '23:59'],
tickformat: '%H:%M'
},
yaxis: {
title: 'Wert in %',
range: [0, 100]
}
};
var plotDiv = document.getElementById('plot');
Plotly.newPlot(plotDiv, [], layout, {responsive: true});
// initialisiere Graph
var data = [ { x: ['00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00'],
y: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
name: 'Channel 1',
mode: 'lines+markers',
line: {
shape: 'spline'
}
},
{
x: ['00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00'],
y: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
name: 'Channel 2',
mode: 'lines+markers',
line: {
shape: 'spline'
}
},
{
x: ['00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00'],
y: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
name: 'Channel 3',
mode: 'lines+markers',
line: {
shape: 'spline'
}
},
{
x: ['00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00'],
y: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
name: 'Channel 4',
mode: 'lines+markers',
line: {
shape: 'spline'
}
}
];
var layout = {
xaxis: {
title: 'Time (hh:mm)',
showgrid: false,
zeroline: false
},
yaxis: {
title: 'Value (%)',
showline: false
}
};
Plotly.newPlot('graph', data, layout);
// initialisiere Graph
var layout = {
title: 'Graph',
xaxis: {
title: 'Uhrzeit'
},
yaxis: {
title: 'Prozent'
},
hovermode: 'closest'
};
var plot_data = [{ x: [],
y: [],
mode: 'lines+markers',
line: { shape: 'spline' }
}];
Plotly.newPlot('graph', plot_data, layout);
// Funktion zum Aktualisieren der Daten
function updateData() {
// Schleife über alle Eingabefelder für die Uhrzeit
for (let i = 0; i < 10; i++) {
// Uhrzeit aus den Eingabefeldern auslesen
let hour = document.getElementById(`hour-${i}`).value;
let minute = document.getElementById(`minute-${i}`).value;
// Schleife über alle Eingabefelder für die Kanäle
for (let j = 1; j <= 4; j++) {
// Wert aus dem Eingabefeld auslesen
let value = parseFloat(document.getElementById(`ch${j}-${i}`).value);
// Datenpunkt aktualisieren
let index = i * 4 + (j - 1);
data[index].x = `${hour}:${minute}`;
data[index].y = value;
}
}
// Daten im Graph aktualisieren
Plotly.update('graph', data, layout);
}
// Event-Listener für alle Eingabefelder registrieren
for (let i = 0; i < 10; i++) {
// Uhrzeit-Eingabefelder
document.getElementById(`hour-${i}`).addEventListener('input', updateData);
document.getElementById(`minute-${i}`).addEventListener('input', updateData);
// Kanal-Eingabefelder
for (let j = 1; j <= 4; j++) {
document.getElementById(`ch${j}-${i}`).addEventListener('input', updateData);
}
}
function sendTCData() {
// Sammle Daten aus Eingabefeldern
var data = [];
for (var i = 0; i < 10; i++) {
var hh = document.getElementById("hh_" + i).value;
var mm = document.getElementById("mm_" + i).value;
var ch1 = document.getElementById("ch1_" + i).value;
var ch2 = document.getElementById("ch2_" + i).value;
var ch3 = document.getElementById("ch3_" + i).value;
var ch4 = document.getElementById("ch4_" + i).value;
data.push({ "hh": hh, "mm": mm, "ch1": ch1, "ch2": ch2, "ch3": ch3, "ch4": ch4 });
}
// Codiere Daten als JSON und URL-encode
var jsonData = encodeURIComponent(JSON.stringify(data));
// Sende Daten an Server
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://{{IP_ADDRESS}}}}/tc_data_block_store?data=" + jsonData);
xhr.send();
}
</script>

View file

@ -371,7 +371,7 @@ bool tc_check_no_data_block()
uint8_t e = EEPROM.read(EEPROM_TIMING_DATA_ADDRESS); uint8_t e = EEPROM.read(EEPROM_TIMING_DATA_ADDRESS);
//Serial.println(e); //Serial.println(e);
if (e > 23) // the maximum value for tis memory section is 23 if (e == 255)
{ {
return true; return true;
} }
@ -416,60 +416,12 @@ void tc_jsonDataBlocksToEEPROM(String json_data_string)
for (uint8_t i = 0; i < NUMBER_OF_TIMER_DATA_BLOCKS; i++) for (uint8_t i = 0; i < NUMBER_OF_TIMER_DATA_BLOCKS; i++)
{ {
JsonObject obj = doc[i]; JsonObject obj = doc[i];
tc_data[i].hh = obj["hour"];
// Check and set the limits of the hour value tc_data[i].mm = obj["min"];
int hour = obj["hour"]; tc_data[i].ch1 = obj["ch1"];
if (hour < 0) { tc_data[i].ch2 = obj["ch2"];
hour = 0; tc_data[i].ch3 = obj["ch3"];
} else if (hour > 23) { tc_data[i].ch4 = obj["ch4"];
hour = 23;
}
tc_data[i].hh = hour;
// Check and set the limits of the minute value
int minute = obj["min"];
if (minute < 0) {
minute = 0;
} else if (minute > 59) {
minute = 59;
}
tc_data[i].mm = minute;
// Check and set the limits of the ch1 value
int ch1 = obj["ch1"];
if (ch1 < 0) {
ch1 = 0;
} else if (ch1 > 255) {
ch1 = 255;
}
tc_data[i].ch1 = ch1;
// Check and set the limits of the ch2 value
int ch2 = obj["ch2"];
if (ch2 < 0) {
ch2 = 0;
} else if (ch2 > 255) {
ch2 = 255;
}
tc_data[i].ch2 = ch2;
// Check and set the limits of the ch3 value
int ch3 = obj["ch3"];
if (ch3 < 0) {
ch3 = 0;
} else if (ch3 > 255) {
ch3 = 255;
}
tc_data[i].ch3 = ch3;
// Check and set the limits of the ch4 value
int ch4 = obj["ch4"];
if (ch4 < 0) {
ch4 = 0;
} else if (ch4 > 255) {
ch4 = 255;
}
tc_data[i].ch4 = ch4;
} }
// Write the tc_data array to the EEPROM // Write the tc_data array to the EEPROM

View file

@ -1,10 +1,4 @@
#!/bin/bash #!/bin/bash
# Remove leading whitespace and comments starting with // cat $1 | sed -e"s/^ *//ig" | sed -e "s/^\/\/.*//ig"
sed -e 's/^[[:space:]]*//' -e '/^\/\/.*/d' $1 |
# Remove one line comments starting with //
sed -e 's/^\/\/.*$//' |
# Remove trailing comments starting with //
sed -e 's/ \/\/.*$//' |
# Remove empty lines
sed '/^\s*$/d'

View file

@ -5,4 +5,3 @@ bash ../../tools/html2string.sh ../html/index_template_middle.html > index_templ
bash ../../tools/html2string.sh ../html/index_template_bottom.html > index_template_bottom.html bash ../../tools/html2string.sh ../html/index_template_bottom.html > index_template_bottom.html
bash ../../tools/html2string.sh ../html/config_template.html > config_template.html bash ../../tools/html2string.sh ../html/config_template.html > config_template.html
bash ../../tools/html2string.sh ../html/light_control_template.html > light_control_template.html bash ../../tools/html2string.sh ../html/light_control_template.html > light_control_template.html
bash ../../tools/html2string.sh ../html/tc_data_edit.html > tc_data_edit.html