diff --git a/3d/Super Vihelmo-Trug-2.stl b/3d/Super Vihelmo-Trug-2.stl new file mode 100644 index 0000000..817abf6 Binary files /dev/null and b/3d/Super Vihelmo-Trug-2.stl differ diff --git a/3d/Super Vihelmo-Trug-3.stl b/3d/Super Vihelmo-Trug-3.stl new file mode 100644 index 0000000..74685c4 Binary files /dev/null and b/3d/Super Vihelmo-Trug-3.stl differ diff --git a/3d/Super Vihelmo-Trug-4.stl b/3d/Super Vihelmo-Trug-4.stl new file mode 100644 index 0000000..b8a0bbf Binary files /dev/null and b/3d/Super Vihelmo-Trug-4.stl differ diff --git a/3d/Super Vihelmo-Trug-5.stl b/3d/Super Vihelmo-Trug-5.stl new file mode 100644 index 0000000..655fdbf Binary files /dev/null and b/3d/Super Vihelmo-Trug-5.stl differ diff --git a/3d/Super Vihelmo-Trug.stl b/3d/Super Vihelmo-Trug.stl new file mode 100644 index 0000000..b4d8798 Binary files /dev/null and b/3d/Super Vihelmo-Trug.stl differ diff --git a/README.md b/README.md index f43b7ae..fa69e73 100644 --- a/README.md +++ b/README.md @@ -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. +Sample schematics (no NodeMCU pins defined in there) + +![Sample schematics](pic/schematics.png) diff --git a/firmware/data/bottom.js b/firmware/data/bottom.js index 976c0d9..8459e2f 100644 --- a/firmware/data/bottom.js +++ b/firmware/data/bottom.js @@ -13,6 +13,7 @@ tabTDE.classList.remove("visible"); amain.classList.add("pure-button-primary"); acfg.classList.remove("pure-button-primary"); atde.classList.remove("pure-button-primary"); +loadGraphData(); }); acfg.addEventListener("click", function() { tabMain.classList.remove("visible"); @@ -50,10 +51,10 @@ 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']); -channel2.push(data['tcdata'][i]['ch2']); -channel3.push(data['tcdata'][i]['ch3']); -channel4.push(data['tcdata'][i]['ch4']); +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']); @@ -130,7 +131,7 @@ tickangle: -45, }, yaxis: { title: 'Brightness', -range: [0, 255], +range: [0, 100], }, shapes: [{ type: 'line', @@ -150,6 +151,119 @@ Plotly.newPlot('plot_chart', [trace1, trace2, trace3, trace4], layout); } setInterval(loadGraphData, 10000); 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() { console.log('----> setting bri and power switch <----'); for (let i = 1; i <= {{LIGHT_COUNT}}; i++) { @@ -196,9 +310,36 @@ var links = document.querySelectorAll('[id^="on"][id$="_off"]'); links.forEach(function(link) { link.addEventListener('click', function(event) { event.preventDefault(); +var id_full = this.id; var id = this.id.replace('on', '').replace('_off', ''); var xhr = new XMLHttpRequest(); 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(); updateLightState(); this.classList.add('pure-button-primary'); @@ -209,9 +350,36 @@ var links = document.querySelectorAll('[id^="on"][id$="_on"]'); links.forEach(function(link) { link.addEventListener('click', function(event) { event.preventDefault(); +var id_full = this.id; 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.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(); updateLightState(); this.classList.add('pure-button-primary'); @@ -231,22 +399,22 @@ headerRow.appendChild(th); table.appendChild(headerRow); for (var i = 1; i <= 10; i++) { var tr = document.createElement("tr"); -var tdHour = createSelectCell(23, 0); +var tdHour = createSelectCell(23, 0, 1); tdHour.id = "hour" + i; tr.appendChild(tdHour); -var tdMinute = createSelectCell(59, 0); +var tdMinute = createSelectCell(59, 0, 1); tdMinute.id = "minute" + i; tr.appendChild(tdMinute); -var tdCh1 = createSelectCell(100, 0); +var tdCh1 = createSelectCell(100, 0, 1); tdCh1.id = "ch1_" + i; tr.appendChild(tdCh1); -var tdCh2 = createSelectCell(100, 0); +var tdCh2 = createSelectCell(100, 0, 1); tdCh2.id = "ch2_" + i; tr.appendChild(tdCh2); -var tdCh3 = createSelectCell(100, 0); +var tdCh3 = createSelectCell(100, 0, 1); tdCh3.id = "ch3_" + i; tr.appendChild(tdCh3); -var tdCh4 = createSelectCell(100, 0); +var tdCh4 = createSelectCell(100, 0, 1); tdCh4.id = "ch4_" + i; tr.appendChild(tdCh4); table.appendChild(tr); @@ -256,9 +424,9 @@ container.innerHTML = ""; container.classList.add("pure-form"); container.appendChild(table); } -function createSelectCell(max, value) { +function createSelectCell(max, value, step) { 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"); option.value = i; option.text = i; @@ -278,11 +446,12 @@ for (var i = 0; i < tcdata.length; i++) { var row = document.getElementById("hour" + (i+1)).parentNode; row.cells[0].childNodes[0].value = tcdata[i].hour; row.cells[1].childNodes[0].value = tcdata[i].min; -row.cells[2].childNodes[0].value = parseInt(tcdata[i].ch1 * 100 / 255); -row.cells[3].childNodes[0].value = parseInt(tcdata[i].ch2 * 100 / 255); -row.cells[4].childNodes[0].value = parseInt(tcdata[i].ch3 * 100 / 255); -row.cells[5].childNodes[0].value = parseInt(tcdata[i].ch4 * 100 / 255); +row.cells[2].childNodes[0].value = parseInt(Math.round(tcdata[i].ch1 * 100 / 255)); +row.cells[3].childNodes[0].value = parseInt(Math.round(tcdata[i].ch2 * 100 / 255)); +row.cells[4].childNodes[0].value = parseInt(Math.round(tcdata[i].ch3 * 100 / 255)); +row.cells[5].childNodes[0].value = parseInt(Math.round(tcdata[i].ch4 * 100 / 255)); } +loadTCGraphData(); }); } 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 jsonData = {tcdata: tcdata, currenttime: currentTime}; -console.log("jsonData = " + JSON.stringify(jsonData)); return JSON.stringify(jsonData); } function sendDataToServer() { var jsonData = createJsonFromTable(); var urlEncodedData = encodeURIComponent(jsonData); var url = 'http://{{IP_ADDRESS}}/tc_data_blocks_store?data=' + urlEncodedData; -console.log("url so save = " + url); var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); -xhr.onreadystatechange = function() { -if (xhr.readyState === 4 && xhr.status === 200) { +xhr.onreadystatechange = function () { +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!'); +} 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(); +loadTCGraphData(); } diff --git a/firmware/data/config_template.html b/firmware/data/config_template.html index 820b72a..da7ca3b 100644 --- a/firmware/data/config_template.html +++ b/firmware/data/config_template.html @@ -1,70 +1,70 @@ -
+
+
+ |
+
+
+
+ |
+
+ |
diff --git a/firmware/html/light_control_template.html b/firmware/html/light_control_template.html
index be21046..bc62ab1 100644
--- a/firmware/html/light_control_template.html
+++ b/firmware/html/light_control_template.html
@@ -7,13 +7,13 @@
OFF
-
+
9
%
- + diff --git a/firmware/html/style.css b/firmware/html/style.css index e39a471..9788312 100644 --- a/firmware/html/style.css +++ b/firmware/html/style.css @@ -40,4 +40,7 @@ cursor: pointer; } .pure-button:hover { background-color: #333; +} +.top-align { +vertical-align: top; } \ No newline at end of file diff --git a/firmware/html/top.js b/firmware/html/top.js index 73dd43b..bf4ddaa 100644 --- a/firmware/html/top.js +++ b/firmware/html/top.js @@ -4,6 +4,34 @@ links.forEach(function(link) { event.preventDefault(); var xhr = new XMLHttpRequest(); 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(); //console.log('tc=true call'); document.getElementById('tc_on').classList.add('pure-button-primary'); @@ -16,6 +44,34 @@ links.forEach(function(link) { event.preventDefault(); var xhr = new XMLHttpRequest(); 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(); //console.log('tc=false call'); document.getElementById('tc_off').classList.add('pure-button-primary'); diff --git a/pic/schematics.png b/pic/schematics.png new file mode 100644 index 0000000..f03a73b Binary files /dev/null and b/pic/schematics.png differ |