Compare commits

...

8 commits

Author SHA1 Message Date
Kai Lauterbach
90b6b36f26 Updated SPIFFS binary 2023-05-07 17:00:28 +02:00
Kai Lauterbach
bc74f68e15 Merge branch 'develop' 2023-05-07 16:57:47 +02:00
Kai Lauterbach
1ca1f3e6e3 Status output implemented - after click on a button 2023-05-07 16:57:24 +02:00
Kai Lauterbach
1564f9b559 Readme updated 2023-05-07 16:30:42 +02:00
Kai Lauterbach
6e35e1baec Added 3D case model and inner electronics holder 2023-05-07 16:29:13 +02:00
Kai Lauterbach
21952bd0e3 PNG of the schematics added. 2023-05-07 16:13:26 +02:00
Kai Lauterbach
3d54da7f75 First automatically updated timing edit plotly graph. 2023-05-07 11:31:52 +02:00
Kai Lauterbach
ba63edfc5f Fixed the range of the lights graph y axis (255 before 100 max after) 2023-05-07 09:45:18 +02:00
23 changed files with 694 additions and 156 deletions

BIN
3d/Super Vihelmo-Trug-2.stl Normal file

Binary file not shown.

BIN
3d/Super Vihelmo-Trug-3.stl Normal file

Binary file not shown.

BIN
3d/Super Vihelmo-Trug-4.stl Normal file

Binary file not shown.

BIN
3d/Super Vihelmo-Trug-5.stl Normal file

Binary file not shown.

BIN
3d/Super Vihelmo-Trug.stl Normal file

Binary file not shown.

View file

@ -25,3 +25,6 @@ All except of the timing control data block.
You have to click at the link "reset timing control data" on the webinterface. You have to click at the link "reset timing control data" on the webinterface.
Sample schematics (no NodeMCU pins defined in there)
![Sample schematics](pic/schematics.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 MiB

After

Width:  |  Height:  |  Size: 2 MiB

View file

@ -13,6 +13,7 @@ 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");
loadGraphData();
}); });
acfg.addEventListener("click", function() { acfg.addEventListener("click", function() {
tabMain.classList.remove("visible"); tabMain.classList.remove("visible");
@ -50,10 +51,10 @@ var channel3 = [];
var channel4 = []; var channel4 = [];
for (var i = 0; i < data['tcdata'].length; i++) { for (var i = 0; i < data['tcdata'].length; i++) {
time.push(data['tcdata'][i]['hour'] + ':' + (data['tcdata'][i]['min'] < 10 ? '0' : '') + data['tcdata'][i]['min']); time.push(data['tcdata'][i]['hour'] + ':' + (data['tcdata'][i]['min'] < 10 ? '0' : '') + data['tcdata'][i]['min']);
channel1.push(data['tcdata'][i]['ch1']); channel1.push(data['tcdata'][i]['ch1'] * 100 / 255);
channel2.push(data['tcdata'][i]['ch2']); channel2.push(data['tcdata'][i]['ch2'] * 100 / 255);
channel3.push(data['tcdata'][i]['ch3']); channel3.push(data['tcdata'][i]['ch3'] * 100 / 255);
channel4.push(data['tcdata'][i]['ch4']); channel4.push(data['tcdata'][i]['ch4'] * 100 / 255);
} }
currenttime.push(data['currenttime']['hour']); currenttime.push(data['currenttime']['hour']);
currenttime.push(data['currenttime']['min']); currenttime.push(data['currenttime']['min']);
@ -130,7 +131,7 @@ tickangle: -45,
}, },
yaxis: { yaxis: {
title: 'Brightness', title: 'Brightness',
range: [0, 255], range: [0, 100],
}, },
shapes: [{ shapes: [{
type: 'line', type: 'line',
@ -150,6 +151,119 @@ Plotly.newPlot('plot_chart', [trace1, trace2, trace3, trace4], layout);
} }
setInterval(loadGraphData, 10000); setInterval(loadGraphData, 10000);
loadGraphData(); loadGraphData();
function loadTCGraphData() {
console.log('----> generate tc data graph <----');
var data = JSON.parse(createJsonFromTable());
var currenttime = [];
var time = [];
var channel1 = [];
var channel2 = [];
var channel3 = [];
var channel4 = [];
for (var i = 0; i < data['tcdata'].length; i++) {
time.push(data['tcdata'][i]['hour'] + ':' + (data['tcdata'][i]['min'] < 10 ? '0' : '') + data['tcdata'][i]['min']);
channel1.push(data['tcdata'][i]['ch1'] * 100 / 255);
channel2.push(data['tcdata'][i]['ch2'] * 100 / 255);
channel3.push(data['tcdata'][i]['ch3'] * 100 / 255);
channel4.push(data['tcdata'][i]['ch4'] * 100 / 255);
}
currenttime.push(data['currenttime']['hour']);
currenttime.push(data['currenttime']['min']);
var currentTimeStr = currenttime[0] + ':' + (currenttime[1] < 10 ? '0' : '') + currenttime[1];
var index = time.indexOf(currentTimeStr);
if (index === -1) {
var lowerIndex = -1;
var upperIndex = -1;
for (var i = 0; i < time.length - 1; i++) {
const currentDate = new Date();
const year = currentDate.getFullYear();
const month = (currentDate.getMonth() + 1).toString().padStart(2, '0');
const day = currentDate.getDate().toString().padStart(2, '0');
const dateString = `${year}-${month}-${day}`;
const start = moment(dateString + ' ' + time[i], 'YYYY-MM-DD HH:mm');
const curr = moment(dateString + ' ' + currentTimeStr, 'YYYY-MM-DD HH:mm');
const end = moment(dateString + ' ' + time[i + 1], 'YYYY-MM-DD HH:mm');
if (curr.isBetween(start, end)) {
lowerIndex = i;
upperIndex = i + 1;
break;
}
}
if (lowerIndex === -1 || upperIndex === -1) {
console.log("Error: Current time not found in time array and not between two elements in time array. Fixing it...");
lowerIndex = 0;
upperIndex = 1;
var tmp1 = time[0].split(':');
currenttime[0] = tmp1[0];
currenttime[1] = tmp1[1];
}
var lowerTime = time[lowerIndex].split(":");
var upperTime = time[upperIndex].split(":");
var timeDiff = (currenttime[0] - lowerTime[0]) + ((currenttime[1] - lowerTime[1]) / 60);
var indexFloat = lowerIndex + timeDiff / ((upperTime[0] - lowerTime[0]) + ((upperTime[1] - lowerTime[1]) / 60));
} else {
}
if (indexFloat > index) {
index = indexFloat;
}
var trace1 = {
x: time,
y: channel1,
name: 'Channel 1',
type: 'scatter',
mode: 'lines+markers',
};
var trace2 = {
x: time,
y: channel2,
name: 'Channel 2',
type: 'scatter',
mode: 'lines+markers',
};
var trace3 = {
x: time,
y: channel3,
name: 'Channel 3',
type: 'scatter',
mode: 'lines+markers',
};
var trace4 = {
x: time,
y: channel4,
name: 'Channel 4',
type: 'scatter',
mode: 'lines+markers',
};
var layout = {
title: 'Timing Control Data Blocks',
xaxis: {
title: 'Time',
tickangle: -45,
},
yaxis: {
title: 'Brightness',
range: [0, 100],
},
shapes: [{
type: 'line',
x0: index,
y0: 0,
x1: index,
y1: 255,
line: {
color: 'lightgrey',
width: 3,
dash: 'dot'
}
}]
};
Plotly.newPlot('tc_plot_chart', [trace1, trace2, trace3, trace4], layout);
}
setInterval(function() {
if (document.getElementById('tab-tde').classList.contains('visible')) {
loadTCGraphData();
}
}, 2000);
function updateLightState() { function updateLightState() {
console.log('----> setting bri and power switch <----'); console.log('----> setting bri and power switch <----');
for (let i = 1; i <= {{LIGHT_COUNT}}; i++) { for (let i = 1; i <= {{LIGHT_COUNT}}; i++) {
@ -196,9 +310,36 @@ var links = document.querySelectorAll('[id^="on"][id$="_off"]');
links.forEach(function(link) { links.forEach(function(link) {
link.addEventListener('click', function(event) { link.addEventListener('click', function(event) {
event.preventDefault(); event.preventDefault();
var id_full = this.id;
var id = this.id.replace('on', '').replace('_off', ''); var id = this.id.replace('on', '').replace('_off', '');
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=false&transition=' + document.getElementById('transition').value, true); xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=false&transition=' + document.getElementById('transition').value, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
var button = document.getElementById(id_full);
if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Disabled!";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
}, 2000);
console.log('Error while sending data to server.');
}
}
};
xhr.send(); xhr.send();
updateLightState(); updateLightState();
this.classList.add('pure-button-primary'); this.classList.add('pure-button-primary');
@ -209,9 +350,36 @@ var links = document.querySelectorAll('[id^="on"][id$="_on"]');
links.forEach(function(link) { links.forEach(function(link) {
link.addEventListener('click', function(event) { link.addEventListener('click', function(event) {
event.preventDefault(); event.preventDefault();
var id_full = this.id;
var id = this.id.replace('on', '').replace('_on', ''); var id = this.id.replace('on', '').replace('_on', '');
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=true&transition=' + document.getElementById('transition').value, true); xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=true&transition=' + document.getElementById('transition').value, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
var button = document.getElementById(id_full);
if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Enabled!";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
}, 2000);
console.log('Error while sending data to server.');
}
}
};
xhr.send(); xhr.send();
updateLightState(); updateLightState();
this.classList.add('pure-button-primary'); this.classList.add('pure-button-primary');
@ -231,22 +399,22 @@ headerRow.appendChild(th);
table.appendChild(headerRow); table.appendChild(headerRow);
for (var i = 1; i <= 10; i++) { for (var i = 1; i <= 10; i++) {
var tr = document.createElement("tr"); var tr = document.createElement("tr");
var tdHour = createSelectCell(23, 0); var tdHour = createSelectCell(23, 0, 1);
tdHour.id = "hour" + i; tdHour.id = "hour" + i;
tr.appendChild(tdHour); tr.appendChild(tdHour);
var tdMinute = createSelectCell(59, 0); var tdMinute = createSelectCell(59, 0, 1);
tdMinute.id = "minute" + i; tdMinute.id = "minute" + i;
tr.appendChild(tdMinute); tr.appendChild(tdMinute);
var tdCh1 = createSelectCell(100, 0); var tdCh1 = createSelectCell(100, 0, 1);
tdCh1.id = "ch1_" + i; tdCh1.id = "ch1_" + i;
tr.appendChild(tdCh1); tr.appendChild(tdCh1);
var tdCh2 = createSelectCell(100, 0); var tdCh2 = createSelectCell(100, 0, 1);
tdCh2.id = "ch2_" + i; tdCh2.id = "ch2_" + i;
tr.appendChild(tdCh2); tr.appendChild(tdCh2);
var tdCh3 = createSelectCell(100, 0); var tdCh3 = createSelectCell(100, 0, 1);
tdCh3.id = "ch3_" + i; tdCh3.id = "ch3_" + i;
tr.appendChild(tdCh3); tr.appendChild(tdCh3);
var tdCh4 = createSelectCell(100, 0); var tdCh4 = createSelectCell(100, 0, 1);
tdCh4.id = "ch4_" + i; tdCh4.id = "ch4_" + i;
tr.appendChild(tdCh4); tr.appendChild(tdCh4);
table.appendChild(tr); table.appendChild(tr);
@ -256,9 +424,9 @@ container.innerHTML = "";
container.classList.add("pure-form"); container.classList.add("pure-form");
container.appendChild(table); container.appendChild(table);
} }
function createSelectCell(max, value) { function createSelectCell(max, value, step) {
var select = document.createElement("select"); var select = document.createElement("select");
for (var i = 0; i <= max; i++) { for (var i = 0; i <= max; i += step) {
var option = document.createElement("option"); var option = document.createElement("option");
option.value = i; option.value = i;
option.text = i; option.text = i;
@ -278,11 +446,12 @@ for (var i = 0; i < tcdata.length; i++) {
var row = document.getElementById("hour" + (i+1)).parentNode; var row = document.getElementById("hour" + (i+1)).parentNode;
row.cells[0].childNodes[0].value = tcdata[i].hour; row.cells[0].childNodes[0].value = tcdata[i].hour;
row.cells[1].childNodes[0].value = tcdata[i].min; row.cells[1].childNodes[0].value = tcdata[i].min;
row.cells[2].childNodes[0].value = parseInt(tcdata[i].ch1 * 100 / 255); row.cells[2].childNodes[0].value = parseInt(Math.round(tcdata[i].ch1 * 100 / 255));
row.cells[3].childNodes[0].value = parseInt(tcdata[i].ch2 * 100 / 255); row.cells[3].childNodes[0].value = parseInt(Math.round(tcdata[i].ch2 * 100 / 255));
row.cells[4].childNodes[0].value = parseInt(tcdata[i].ch3 * 100 / 255); row.cells[4].childNodes[0].value = parseInt(Math.round(tcdata[i].ch3 * 100 / 255));
row.cells[5].childNodes[0].value = parseInt(tcdata[i].ch4 * 100 / 255); row.cells[5].childNodes[0].value = parseInt(Math.round(tcdata[i].ch4 * 100 / 255));
} }
loadTCGraphData();
}); });
} }
function createJsonFromTable() { function createJsonFromTable() {
@ -300,20 +469,40 @@ tcdata.push({hour: hour, min: min, ch1: ch1, ch2: ch2, ch3: ch3, ch4: ch4});
} }
var currentTime = {hour: new Date().getHours(), min: new Date().getMinutes()}; var currentTime = {hour: new Date().getHours(), min: new Date().getMinutes()};
var jsonData = {tcdata: tcdata, currenttime: currentTime}; var jsonData = {tcdata: tcdata, currenttime: currentTime};
console.log("jsonData = " + JSON.stringify(jsonData));
return JSON.stringify(jsonData); return JSON.stringify(jsonData);
} }
function sendDataToServer() { function sendDataToServer() {
var jsonData = createJsonFromTable(); var jsonData = createJsonFromTable();
var urlEncodedData = encodeURIComponent(jsonData); var urlEncodedData = encodeURIComponent(jsonData);
var url = 'http://{{IP_ADDRESS}}/tc_data_blocks_store?data=' + urlEncodedData; var url = 'http://{{IP_ADDRESS}}/tc_data_blocks_store?data=' + urlEncodedData;
console.log("url so save = " + url);
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', url, true); xhr.open('GET', url, true);
xhr.onreadystatechange = function() { xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) { if (xhr.readyState === 4) {
var button = document.getElementById("save-button");
if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Saved!";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "save";
}, 2000);
console.log('Data successfully sent to server!'); console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "save";
}, 2000);
console.log('Error while sending data to server.');
}
} }
}; };
xhr.send(); xhr.send();
loadTCGraphData();
} }

View file

@ -6,10 +6,20 @@
<strong>Timming control data editor</strong> <strong>Timming control data editor</strong>
</label> </label>
<br> <br>
<div id="table-container"> <table>
<tr>
<td>
<div id="table-container" class="top-align">
</div> </div>
</td>
<td>
<div id="tc_plot_chart" class="top-align">
</div>
</td>
</tr>
</table>
<br> <br>
<a href="#" class="pure-button pure-button-primary" onclick="sendDataToServer();">save</a> <a href="#" id="save-button" class="pure-button pure-button-primary" onclick="sendDataToServer();">save</a>
</div> </div>
</div> <!-- end of tab-tde --> </div> <!-- end of tab-tde -->
<script src="http://{{IP_ADDRESS}}/js_bottom"> <script src="http://{{IP_ADDRESS}}/js_bottom">

View file

@ -1,7 +1,7 @@
<!-- middle --> <!-- middle -->
</td> </td>
<td> <td>
<div id="plot_chart"></div> <div id="plot_chart" class="top-align"></div>
</td> </td>
</tr> </tr>
</table> </table>

View file

@ -47,4 +47,4 @@
<br> <br>
<table border=0> <table border=0>
<tr> <tr>
<td> <td class="top-align">

View file

@ -7,13 +7,13 @@
<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}}">Target brightness</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">Actual Bri.</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>

View file

@ -41,3 +41,6 @@ cursor: pointer;
.pure-button:hover { .pure-button:hover {
background-color: #333; background-color: #333;
} }
.top-align {
vertical-align: top;
}

View file

@ -4,6 +4,32 @@ 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.onreadystatechange = function () {
if (xhr.readyState === 4) {
var button = document.getElementById("tc_on");
if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Enabled!";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
}, 2000);
console.log('Error while sending data to server.');
}
}
};
xhr.send(); xhr.send();
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');
@ -15,6 +41,32 @@ 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.onreadystatechange = function () {
if (xhr.readyState === 4) {
var button = document.getElementById("tc_off");
if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Disabled!";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
}, 2000);
console.log('Error while sending data to server.');
}
}
};
xhr.send(); xhr.send();
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');

View file

@ -19,6 +19,8 @@ function addTabListener() {
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");
loadGraphData(); // reload the graph
}); });
acfg.addEventListener("click", function() { acfg.addEventListener("click", function() {
@ -64,10 +66,10 @@ function loadGraphData() {
var channel4 = []; var channel4 = [];
for (var i = 0; i < data['tcdata'].length; i++) { for (var i = 0; i < data['tcdata'].length; i++) {
time.push(data['tcdata'][i]['hour'] + ':' + (data['tcdata'][i]['min'] < 10 ? '0' : '') + data['tcdata'][i]['min']); time.push(data['tcdata'][i]['hour'] + ':' + (data['tcdata'][i]['min'] < 10 ? '0' : '') + data['tcdata'][i]['min']);
channel1.push(data['tcdata'][i]['ch1']); channel1.push(data['tcdata'][i]['ch1'] * 100 / 255);
channel2.push(data['tcdata'][i]['ch2']); channel2.push(data['tcdata'][i]['ch2'] * 100 / 255);
channel3.push(data['tcdata'][i]['ch3']); channel3.push(data['tcdata'][i]['ch3'] * 100 / 255);
channel4.push(data['tcdata'][i]['ch4']); channel4.push(data['tcdata'][i]['ch4'] * 100 / 255);
} }
currenttime.push(data['currenttime']['hour']); currenttime.push(data['currenttime']['hour']);
currenttime.push(data['currenttime']['min']); currenttime.push(data['currenttime']['min']);
@ -155,7 +157,7 @@ function loadGraphData() {
}, },
yaxis: { yaxis: {
title: 'Brightness', title: 'Brightness',
range: [0, 255], range: [0, 100],
}, },
shapes: [{ shapes: [{
type: 'line', type: 'line',
@ -176,6 +178,135 @@ function loadGraphData() {
setInterval(loadGraphData, 10000); setInterval(loadGraphData, 10000);
loadGraphData(); loadGraphData();
function loadTCGraphData() {
console.log('----> generate tc data graph <----');
var data = JSON.parse(createJsonFromTable());
//console.log(data);
var currenttime = [];
var time = [];
var channel1 = [];
var channel2 = [];
var channel3 = [];
var channel4 = [];
for (var i = 0; i < data['tcdata'].length; i++) {
time.push(data['tcdata'][i]['hour'] + ':' + (data['tcdata'][i]['min'] < 10 ? '0' : '') + data['tcdata'][i]['min']);
channel1.push(data['tcdata'][i]['ch1'] * 100 / 255);
channel2.push(data['tcdata'][i]['ch2'] * 100 / 255);
channel3.push(data['tcdata'][i]['ch3'] * 100 / 255);
channel4.push(data['tcdata'][i]['ch4'] * 100 / 255);
}
currenttime.push(data['currenttime']['hour']);
currenttime.push(data['currenttime']['min']);
//console.log(currenttime);
var currentTimeStr = currenttime[0] + ':' + (currenttime[1] < 10 ? '0' : '') + currenttime[1];
var index = time.indexOf(currentTimeStr);
if (index === -1) {
var lowerIndex = -1;
var upperIndex = -1;
for (var i = 0; i < time.length - 1; i++) {
//console.log(time[i] + ' <= ' + currentTimeStr + ' >= ' + time[i + 1]);
const currentDate = new Date();
const year = currentDate.getFullYear();
const month = (currentDate.getMonth() + 1).toString().padStart(2, '0');
const day = currentDate.getDate().toString().padStart(2, '0');
const dateString = `${year}-${month}-${day}`;
const start = moment(dateString + ' ' + time[i], 'YYYY-MM-DD HH:mm');
const curr = moment(dateString + ' ' + currentTimeStr, 'YYYY-MM-DD HH:mm');
const end = moment(dateString + ' ' + time[i + 1], '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'));
//console.log(curr.isBetween(start, end));
if (curr.isBetween(start, end)) {
lowerIndex = i;
upperIndex = i + 1;
break;
}
}
//console.log('lowerIndex=' + lowerIndex);
//console.log('upperIndex=' + upperIndex);
if (lowerIndex === -1 || upperIndex === -1) {
console.log("Error: Current time not found in time array and not between two elements in time array. Fixing it...");
lowerIndex = 0;
upperIndex = 1;
var tmp1 = time[0].split(':');
//console.log('tmp1 = ' + tmp1);
currenttime[0] = tmp1[0];
currenttime[1] = tmp1[1];
}
var lowerTime = time[lowerIndex].split(":");
var upperTime = time[upperIndex].split(":");
var timeDiff = (currenttime[0] - lowerTime[0]) + ((currenttime[1] - lowerTime[1]) / 60);
var indexFloat = lowerIndex + timeDiff / ((upperTime[0] - lowerTime[0]) + ((upperTime[1] - lowerTime[1]) / 60));
//console.log("Index (float): " + indexFloat);
} else {
//console.log("Index (integer): " + index);
//console.log("Index (float): " + index);
}
if (indexFloat > index) {
index = indexFloat;
}
//console.log("index in graph >>>" + index);
var trace1 = {
x: time,
y: channel1,
name: 'Channel 1',
type: 'scatter',
mode: 'lines+markers',
};
var trace2 = {
x: time,
y: channel2,
name: 'Channel 2',
type: 'scatter',
mode: 'lines+markers',
};
var trace3 = {
x: time,
y: channel3,
name: 'Channel 3',
type: 'scatter',
mode: 'lines+markers',
};
var trace4 = {
x: time,
y: channel4,
name: 'Channel 4',
type: 'scatter',
mode: 'lines+markers',
};
var layout = {
title: 'Timing Control Data Blocks',
xaxis: {
title: 'Time',
tickangle: -45,
},
yaxis: {
title: 'Brightness',
range: [0, 100],
},
shapes: [{
type: 'line',
x0: index,
y0: 0,
x1: index,
y1: 255,
line: {
color: 'lightgrey',
width: 3,
dash: 'dot'
}
}]
};
Plotly.newPlot('tc_plot_chart', [trace1, trace2, trace3, trace4], layout);
}
setInterval(function() {
if (document.getElementById('tab-tde').classList.contains('visible')) {
loadTCGraphData();
}
}, 2000);
function updateLightState() { function updateLightState() {
console.log('----> setting bri and power switch <----'); console.log('----> setting bri and power switch <----');
for (let i = 1; i <= {{LIGHT_COUNT}}; i++) { for (let i = 1; i <= {{LIGHT_COUNT}}; i++) {
@ -230,10 +361,39 @@ links.forEach(function(link) {
// Verhindere, dass der Link die Seite neu lädt // Verhindere, dass der Link die Seite neu lädt
event.preventDefault(); event.preventDefault();
// Extrahiere die Zahl aus der ID des Links // Extrahiere die Zahl aus der ID des Links
var id_full = this.id;
var id = this.id.replace('on', '').replace('_off', ''); var id = this.id.replace('on', '').replace('_off', '');
// Erstelle eine neue Anfrage an die entsprechende URL // Erstelle eine neue Anfrage an die entsprechende URL
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=false&transition=' + document.getElementById('transition').value, true); xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=false&transition=' + document.getElementById('transition').value, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
var button = document.getElementById(id_full);
if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Disabled!";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
}, 2000);
console.log('Error while sending data to server.');
}
}
};
// Sende die Anfrage im Hintergrund // Sende die Anfrage im Hintergrund
xhr.send(); xhr.send();
updateLightState(); updateLightState();
@ -249,10 +409,39 @@ links.forEach(function(link) {
// Verhindere, dass der Link die Seite neu lädt // Verhindere, dass der Link die Seite neu lädt
event.preventDefault(); event.preventDefault();
// Extrahiere die Zahl aus der ID des Links // Extrahiere die Zahl aus der ID des Links
var id_full = this.id;
var id = this.id.replace('on', '').replace('_on', ''); var id = this.id.replace('on', '').replace('_on', '');
// Erstelle eine neue Anfrage an die entsprechende URL // Erstelle eine neue Anfrage an die entsprechende URL
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=true&transition=' + document.getElementById('transition').value, true); xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=true&transition=' + document.getElementById('transition').value, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
var button = document.getElementById(id_full);
if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Enabled!";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
}, 2000);
console.log('Error while sending data to server.');
}
}
};
// Sende die Anfrage im Hintergrund // Sende die Anfrage im Hintergrund
xhr.send(); xhr.send();
updateLightState(); updateLightState();
@ -283,32 +472,32 @@ function createTable() {
var tr = document.createElement("tr"); var tr = document.createElement("tr");
// Stunde // Stunde
var tdHour = createSelectCell(23, 0); var tdHour = createSelectCell(23, 0, 1);
tdHour.id = "hour" + i; tdHour.id = "hour" + i;
tr.appendChild(tdHour); tr.appendChild(tdHour);
// Minute // Minute
var tdMinute = createSelectCell(59, 0); var tdMinute = createSelectCell(59, 0, 1);
tdMinute.id = "minute" + i; tdMinute.id = "minute" + i;
tr.appendChild(tdMinute); tr.appendChild(tdMinute);
// ch1 // ch1
var tdCh1 = createSelectCell(100, 0); var tdCh1 = createSelectCell(100, 0, 1);
tdCh1.id = "ch1_" + i; tdCh1.id = "ch1_" + i;
tr.appendChild(tdCh1); tr.appendChild(tdCh1);
// ch2 // ch2
var tdCh2 = createSelectCell(100, 0); var tdCh2 = createSelectCell(100, 0, 1);
tdCh2.id = "ch2_" + i; tdCh2.id = "ch2_" + i;
tr.appendChild(tdCh2); tr.appendChild(tdCh2);
// ch3 // ch3
var tdCh3 = createSelectCell(100, 0); var tdCh3 = createSelectCell(100, 0, 1);
tdCh3.id = "ch3_" + i; tdCh3.id = "ch3_" + i;
tr.appendChild(tdCh3); tr.appendChild(tdCh3);
// ch4 // ch4
var tdCh4 = createSelectCell(100, 0); var tdCh4 = createSelectCell(100, 0, 1);
tdCh4.id = "ch4_" + i; tdCh4.id = "ch4_" + i;
tr.appendChild(tdCh4); tr.appendChild(tdCh4);
@ -321,12 +510,12 @@ function createTable() {
container.appendChild(table); container.appendChild(table);
} }
function createSelectCell(max, value) { function createSelectCell(max, value, step) {
// Erstelle ein neues select-Element // Erstelle ein neues select-Element
var select = document.createElement("select"); var select = document.createElement("select");
// Füge Optionen hinzu // Füge Optionen hinzu
for (var i = 0; i <= max; i++) { for (var i = 0; i <= max; i += step) {
var option = document.createElement("option"); var option = document.createElement("option");
option.value = i; option.value = i;
option.text = i; option.text = i;
@ -355,11 +544,13 @@ function fillTableFromJson() {
var row = document.getElementById("hour" + (i+1)).parentNode; var row = document.getElementById("hour" + (i+1)).parentNode;
row.cells[0].childNodes[0].value = tcdata[i].hour; row.cells[0].childNodes[0].value = tcdata[i].hour;
row.cells[1].childNodes[0].value = tcdata[i].min; row.cells[1].childNodes[0].value = tcdata[i].min;
row.cells[2].childNodes[0].value = parseInt(tcdata[i].ch1 * 100 / 255); row.cells[2].childNodes[0].value = parseInt(Math.round(tcdata[i].ch1 * 100 / 255));
row.cells[3].childNodes[0].value = parseInt(tcdata[i].ch2 * 100 / 255); row.cells[3].childNodes[0].value = parseInt(Math.round(tcdata[i].ch2 * 100 / 255));
row.cells[4].childNodes[0].value = parseInt(tcdata[i].ch3 * 100 / 255); row.cells[4].childNodes[0].value = parseInt(Math.round(tcdata[i].ch3 * 100 / 255));
row.cells[5].childNodes[0].value = parseInt(tcdata[i].ch4 * 100 / 255); row.cells[5].childNodes[0].value = parseInt(Math.round(tcdata[i].ch4 * 100 / 255));
} }
loadTCGraphData();
}); });
} }
@ -380,7 +571,7 @@ function createJsonFromTable() {
} }
var currentTime = {hour: new Date().getHours(), min: new Date().getMinutes()}; var currentTime = {hour: new Date().getHours(), min: new Date().getMinutes()};
var jsonData = {tcdata: tcdata, currenttime: currentTime}; var jsonData = {tcdata: tcdata, currenttime: currentTime};
console.log("jsonData = " + JSON.stringify(jsonData)); //console.log("jsonData = " + JSON.stringify(jsonData));
return JSON.stringify(jsonData); return JSON.stringify(jsonData);
} }
@ -388,14 +579,34 @@ function sendDataToServer() {
var jsonData = createJsonFromTable(); var jsonData = createJsonFromTable();
var urlEncodedData = encodeURIComponent(jsonData); var urlEncodedData = encodeURIComponent(jsonData);
var url = 'http://{{IP_ADDRESS}}/tc_data_blocks_store?data=' + urlEncodedData; var url = 'http://{{IP_ADDRESS}}/tc_data_blocks_store?data=' + urlEncodedData;
console.log("url so save = " + url);
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', url, true); xhr.open('GET', url, true);
xhr.onreadystatechange = function() { xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) { if (xhr.readyState === 4) {
console.log('Data successfully sent to server!'); var button = document.getElementById("save-button");
} if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Saved!";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "save";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "save";
}, 2000);
console.log('Error while sending data to server.');
}
}
}; };
xhr.send(); xhr.send();
} loadTCGraphData(); // update the tc data graph
}

View file

@ -6,10 +6,21 @@
<strong>Timming control data editor</strong> <strong>Timming control data editor</strong>
</label> </label>
<br> <br>
<div id="table-container"> <table>
</div> <tr>
<td>
<div id="table-container" class="top-align">
</div>
</td>
<td>
<div id="tc_plot_chart" class="top-align">
</div>
</td>
</tr>
</table>
<br> <br>
<a href="#" class="pure-button pure-button-primary" onclick="sendDataToServer();">save</a> <a href="#" id="save-button" class="pure-button pure-button-primary" onclick="sendDataToServer();">save</a>
</div> </div>
</div> <!-- end of tab-tde --> </div> <!-- end of tab-tde -->

View file

@ -1,7 +1,7 @@
<!-- middle --> <!-- middle -->
</td> </td>
<td> <td>
<div id="plot_chart"></div> <div id="plot_chart" class="top-align"></div>
</td> </td>
</tr> </tr>
</table> </table>

View file

@ -47,5 +47,5 @@
<br> <br>
<table border=0> <table border=0>
<tr> <tr>
<td> <td class="top-align">

View file

@ -7,13 +7,13 @@
<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}}">Target brightness</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">Actual Bri.</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>

View file

@ -41,3 +41,6 @@ cursor: pointer;
.pure-button:hover { .pure-button:hover {
background-color: #333; background-color: #333;
} }
.top-align {
vertical-align: top;
}

View file

@ -4,6 +4,34 @@ links.forEach(function(link) {
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.onreadystatechange = function () {
if (xhr.readyState === 4) {
var button = document.getElementById("tc_on");
if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Enabled!";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
}, 2000);
console.log('Error while sending data to server.');
}
}
};
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');
@ -16,6 +44,34 @@ links.forEach(function(link) {
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.onreadystatechange = function () {
if (xhr.readyState === 4) {
var button = document.getElementById("tc_off");
if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Disabled!";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
}, 2000);
console.log('Error while sending data to server.');
}
}
};
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');

BIN
pic/schematics.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 KiB