diff --git a/firmware/data/bottom.js b/firmware/data/bottom.js index 8459e2f..3682501 100644 --- a/firmware/data/bottom.js +++ b/firmware/data/bottom.js @@ -190,7 +190,7 @@ 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..."); +console.log("Warning: 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(':'); @@ -336,6 +336,7 @@ button.classList.remove("error"); button.classList.add("pure-button-primary"); button.innerHTML = "OFF"; }, 2000); +showToast('Error while sending data to server.', 'error'); console.log('Error while sending data to server.'); } } @@ -376,6 +377,7 @@ button.classList.remove("error"); button.classList.add("pure-button-primary"); button.innerHTML = "ON"; }, 2000); +showToast('Error while sending data to server.', 'error'); console.log('Error while sending data to server.'); } } @@ -405,18 +407,11 @@ tr.appendChild(tdHour); var tdMinute = createSelectCell(59, 0, 1); tdMinute.id = "minute" + i; tr.appendChild(tdMinute); -var tdCh1 = createSelectCell(100, 0, 1); -tdCh1.id = "ch1_" + i; -tr.appendChild(tdCh1); -var tdCh2 = createSelectCell(100, 0, 1); -tdCh2.id = "ch2_" + i; -tr.appendChild(tdCh2); -var tdCh3 = createSelectCell(100, 0, 1); -tdCh3.id = "ch3_" + i; -tr.appendChild(tdCh3); -var tdCh4 = createSelectCell(100, 0, 1); -tdCh4.id = "ch4_" + i; -tr.appendChild(tdCh4); +for (var j = 1; j <=4; j++) +{ +var tdCh = createSlider("ch" + j + "_" + i, 100, 0, 1); +tr.appendChild(tdCh); +} table.appendChild(tr); } var container = document.getElementById("table-container"); @@ -424,6 +419,36 @@ container.innerHTML = ""; container.classList.add("pure-form"); container.appendChild(table); } +function createSlider(id, max, value, step) { +var input = document.createElement("input"); +input.type = "range"; +input.min = 0; +input.max = max; +input.step = step; +input.value = value; +input.classList.add("pure-slider-range"); +if (id.startsWith("ch1_")) { +input.style.backgroundColor = "blue"; +} else if (id.startsWith("ch2_")) { +input.style.backgroundColor = "orange"; +} else if (id.startsWith("ch3_")) { +input.style.backgroundColor = "green"; +} else if (id.startsWith("ch4_")) { +input.style.backgroundColor = "red"; +} +div = document.createElement("div"); +div.appendChild(input); +var span = document.createElement("span"); +span.innerHTML = " " + value + " %"; +div.appendChild(span); +input.oninput = function() { +span.innerHTML = " " + this.value + " %"; +}; +var td = document.createElement("td"); +td.id = id; +td.appendChild(div); +return td; +} function createSelectCell(max, value, step) { var select = document.createElement("select"); for (var i = 0; i <= max; i += step) { @@ -446,10 +471,14 @@ 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(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)); +row.cells[2].childNodes[0].childNodes[0].value = parseInt(Math.round(tcdata[i].ch1 * 100 / 255)); +row.cells[2].childNodes[0].childNodes[1].innerHTML = " " + row.cells[2].childNodes[0].childNodes[0].value + " %"; +row.cells[3].childNodes[0].childNodes[0].value = parseInt(Math.round(tcdata[i].ch2 * 100 / 255)); +row.cells[3].childNodes[0].childNodes[1].innerHTML = " " + row.cells[3].childNodes[0].childNodes[0].value + " %"; +row.cells[4].childNodes[0].childNodes[0].value = parseInt(Math.round(tcdata[i].ch3 * 100 / 255)); +row.cells[4].childNodes[0].childNodes[1].innerHTML = " " + row.cells[4].childNodes[0].childNodes[0].value + " %"; +row.cells[5].childNodes[0].childNodes[0].value = parseInt(Math.round(tcdata[i].ch4 * 100 / 255)); +row.cells[5].childNodes[0].childNodes[1].innerHTML = " " + row.cells[5].childNodes[0].childNodes[0].value + " %"; } loadTCGraphData(); }); @@ -457,22 +486,42 @@ loadTCGraphData(); function createJsonFromTable() { var tableRows = document.querySelectorAll("table tr"); var tcdata = []; +var timeArr = []; for (var i = 1; i <= 10; i++) { var row = document.getElementById("hour" + i).parentNode; var hour = parseInt(row.cells[0].childNodes[0].value); var min = parseInt(row.cells[1].childNodes[0].value); -var ch1 = Math.round(parseInt(row.cells[2].childNodes[0].value) * 2.55); -var ch2 = Math.round(parseInt(row.cells[3].childNodes[0].value) * 2.55); -var ch3 = Math.round(parseInt(row.cells[4].childNodes[0].value) * 2.55); -var ch4 = Math.round(parseInt(row.cells[5].childNodes[0].value) * 2.55); +timeArr.push(hour * 60 + min); +var ch1 = Math.round(parseInt(row.cells[2].childNodes[0].childNodes[0].value) * 2.55); +var ch2 = Math.round(parseInt(row.cells[3].childNodes[0].childNodes[0].value) * 2.55); +var ch3 = Math.round(parseInt(row.cells[4].childNodes[0].childNodes[0].value) * 2.55); +var ch4 = Math.round(parseInt(row.cells[5].childNodes[0].childNodes[0].value) * 2.55); tcdata.push({hour: hour, min: min, ch1: ch1, ch2: ch2, ch3: ch3, ch4: ch4}); } +for (var i = 0; i < timeArr.length - 1; i++) { +if (timeArr[i] >= timeArr[i + 1]) { +showToast('Error while verifying timing control data. The timestamps are not incrementing.', 'error'); +return null; +} +} var currentTime = {hour: new Date().getHours(), min: new Date().getMinutes()}; var jsonData = {tcdata: tcdata, currenttime: currentTime}; return JSON.stringify(jsonData); } function sendDataToServer() { var jsonData = createJsonFromTable(); +if (!jsonData) { +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 generating timing control data.'); +return; +} var urlEncodedData = encodeURIComponent(jsonData); var url = 'http://{{IP_ADDRESS}}/tc_data_blocks_store?data=' + urlEncodedData; var xhr = new XMLHttpRequest(); @@ -499,6 +548,7 @@ button.classList.remove("error"); button.classList.add("pure-button-primary"); button.innerHTML = "save"; }, 2000); +showToast('Error while sending timing control data to server.', 'error'); console.log('Error while sending data to server.'); } } @@ -506,3 +556,19 @@ console.log('Error while sending data to server.'); xhr.send(); loadTCGraphData(); } +function showToast(message, type) { +const toast = document.querySelector('.toast'); +if (toast) { +toast.textContent = message; +toast.classList.remove('success', 'error'); +if (type === 'success') { +toast.classList.add('success'); +} else if (type === 'error') { +toast.classList.add('error'); +} +toast.style.opacity = 1; +setTimeout(() => { +toast.style.opacity = 0; +}, 5000); +} +} diff --git a/firmware/data/index_template_top.html b/firmware/data/index_template_top.html index 66e10a9..7345687 100644 --- a/firmware/data/index_template_top.html +++ b/firmware/data/index_template_top.html @@ -15,6 +15,7 @@

{{LIGHT_NAME}}

+
update @@ -44,7 +45,6 @@
-
diff --git a/firmware/data/style.css b/firmware/data/style.css index 9788312..caa7f53 100644 --- a/firmware/data/style.css +++ b/firmware/data/style.css @@ -43,4 +43,24 @@ background-color: #333; } .top-align { vertical-align: top; +} +.toast { +position: fixed; +bottom: 10px; +left: 50%; +transform: translateX(-50%); +padding: 10px; +border-radius: 5px; +color: #fff; +font-size: 16px; +font-weight: bold; +text-align: center; +opacity: 0; +transition: opacity 0.5s ease-in-out; +} +.toast.success { +background-color: #4CAF50; +} +.toast.error { +background-color: #f44336; } \ No newline at end of file diff --git a/firmware/data/top.js b/firmware/data/top.js index 7c1839a..559e94e 100644 --- a/firmware/data/top.js +++ b/firmware/data/top.js @@ -26,6 +26,7 @@ button.classList.remove("error"); button.classList.add("pure-button-primary"); button.innerHTML = "ON"; }, 2000); +showToast('Error while sending data to server.', 'error'); console.log('Error while sending data to server.'); } } @@ -63,6 +64,7 @@ button.classList.remove("error"); button.classList.add("pure-button-primary"); button.innerHTML = "OFF"; }, 2000); +showToast('Error while sending data to server.', 'error'); console.log('Error while sending data to server.'); } } @@ -84,6 +86,7 @@ if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } }).catch(error => { +showToast(`Error sending slider value to ${url}: ${error}`, 'error'); console.error(`Error sending slider value to ${url}: ${error}`); }); }, 500); diff --git a/firmware/html/bottom.js b/firmware/html/bottom.js index 69dc709..7b6b029 100644 --- a/firmware/html/bottom.js +++ b/firmware/html/bottom.js @@ -225,7 +225,7 @@ function loadTCGraphData() { //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..."); + console.log("Warning: 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(':'); @@ -389,6 +389,7 @@ links.forEach(function(link) { button.classList.add("pure-button-primary"); button.innerHTML = "OFF"; }, 2000); + showToast('Error while sending data to server.', 'error'); console.log('Error while sending data to server.'); } } @@ -437,6 +438,7 @@ links.forEach(function(link) { button.classList.add("pure-button-primary"); button.innerHTML = "ON"; }, 2000); + showToast('Error while sending data to server.', 'error'); console.log('Error while sending data to server.'); } } @@ -481,25 +483,12 @@ function createTable() { tdMinute.id = "minute" + i; tr.appendChild(tdMinute); - // ch1 - var tdCh1 = createSelectCell(100, 0, 1); - tdCh1.id = "ch1_" + i; - tr.appendChild(tdCh1); - - // ch2 - var tdCh2 = createSelectCell(100, 0, 1); - tdCh2.id = "ch2_" + i; - tr.appendChild(tdCh2); - - // ch3 - var tdCh3 = createSelectCell(100, 0, 1); - tdCh3.id = "ch3_" + i; - tr.appendChild(tdCh3); - - // ch4 - var tdCh4 = createSelectCell(100, 0, 1); - tdCh4.id = "ch4_" + i; - tr.appendChild(tdCh4); + for (var j = 1; j <=4; j++) + { + // chj_i + var tdCh = createSlider("ch" + j + "_" + i, 100, 0, 1); + tr.appendChild(tdCh); + } table.appendChild(tr); } @@ -509,7 +498,49 @@ function createTable() { container.classList.add("pure-form"); container.appendChild(table); } - + +function createSlider(id, max, value, step) { + // Create a new input element of type range + var input = document.createElement("input"); + input.type = "range"; + input.min = 0; + input.max = max; + input.step = step; + input.value = value; + input.classList.add("pure-slider-range"); + // Change the color of the slider based on the id + if (id.startsWith("ch1_")) { + input.style.backgroundColor = "blue"; + } else if (id.startsWith("ch2_")) { + input.style.backgroundColor = "orange"; + } else if (id.startsWith("ch3_")) { + input.style.backgroundColor = "green"; + } else if (id.startsWith("ch4_")) { + input.style.backgroundColor = "red"; + } + + div = document.createElement("div"); + div.appendChild(input); + + // Create a new span element to contain the value of the slider + var span = document.createElement("span"); + span.innerHTML = " " + value + " %"; + div.appendChild(span); + + // Update the span element when the value of the slider changes + input.oninput = function() { + span.innerHTML = " " + this.value + " %"; + }; + + // Create a new td element to contain the div element + var td = document.createElement("td"); + td.id = id; + td.appendChild(div); + + // Return the td element + return td; +} + function createSelectCell(max, value, step) { // Erstelle ein neues select-Element var select = document.createElement("select"); @@ -532,7 +563,7 @@ function createSelectCell(max, value, step) { // Gib die Zelle zurück return row; } - + function fillTableFromJson() { // Lade JSON-Daten fetch('http://{{IP_ADDRESS}}/tc_data_blocks_read') @@ -544,10 +575,18 @@ function fillTableFromJson() { 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(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)); + + row.cells[2].childNodes[0].childNodes[0].value = parseInt(Math.round(tcdata[i].ch1 * 100 / 255)); + row.cells[2].childNodes[0].childNodes[1].innerHTML = " " + row.cells[2].childNodes[0].childNodes[0].value + " %"; + + row.cells[3].childNodes[0].childNodes[0].value = parseInt(Math.round(tcdata[i].ch2 * 100 / 255)); + row.cells[3].childNodes[0].childNodes[1].innerHTML = " " + row.cells[3].childNodes[0].childNodes[0].value + " %"; + + row.cells[4].childNodes[0].childNodes[0].value = parseInt(Math.round(tcdata[i].ch3 * 100 / 255)); + row.cells[4].childNodes[0].childNodes[1].innerHTML = " " + row.cells[4].childNodes[0].childNodes[0].value + " %"; + + row.cells[5].childNodes[0].childNodes[0].value = parseInt(Math.round(tcdata[i].ch4 * 100 / 255)); + row.cells[5].childNodes[0].childNodes[1].innerHTML = " " + row.cells[5].childNodes[0].childNodes[0].value + " %"; } loadTCGraphData(); @@ -557,26 +596,51 @@ function fillTableFromJson() { function createJsonFromTable() { var tableRows = document.querySelectorAll("table tr"); var tcdata = []; + + // Speichert die Zeitangaben (hour, minute) in einem Array + var timeArr = []; for (var i = 1; i <= 10; i++) { - - var row = document.getElementById("hour" + i).parentNode; - var hour = parseInt(row.cells[0].childNodes[0].value); - var min = parseInt(row.cells[1].childNodes[0].value); - var ch1 = Math.round(parseInt(row.cells[2].childNodes[0].value) * 2.55); - var ch2 = Math.round(parseInt(row.cells[3].childNodes[0].value) * 2.55); - var ch3 = Math.round(parseInt(row.cells[4].childNodes[0].value) * 2.55); - var ch4 = Math.round(parseInt(row.cells[5].childNodes[0].value) * 2.55); - - tcdata.push({hour: hour, min: min, ch1: ch1, ch2: ch2, ch3: ch3, ch4: ch4}); + var row = document.getElementById("hour" + i).parentNode; + var hour = parseInt(row.cells[0].childNodes[0].value); + var min = parseInt(row.cells[1].childNodes[0].value); + timeArr.push(hour * 60 + min); // Speichert die Zeitangaben als Minuten seit Mitternacht + var ch1 = Math.round(parseInt(row.cells[2].childNodes[0].childNodes[0].value) * 2.55); + var ch2 = Math.round(parseInt(row.cells[3].childNodes[0].childNodes[0].value) * 2.55); + var ch3 = Math.round(parseInt(row.cells[4].childNodes[0].childNodes[0].value) * 2.55); + var ch4 = Math.round(parseInt(row.cells[5].childNodes[0].childNodes[0].value) * 2.55); + tcdata.push({hour: hour, min: min, ch1: ch1, ch2: ch2, ch3: ch3, ch4: ch4}); } + + // Überprüft, ob die Zeitangaben von datensatz i=0 bis i=9 aufsteigend sind + for (var i = 0; i < timeArr.length - 1; i++) { + if (timeArr[i] >= timeArr[i + 1]) { + showToast('Error while verifying timing control data. The timestamps are not incrementing.', 'error'); + return null; + } + } + 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(); + + if (!jsonData) { + 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 generating timing control data.'); + return; + } + var urlEncodedData = encodeURIComponent(jsonData); var url = 'http://{{IP_ADDRESS}}/tc_data_blocks_store?data=' + urlEncodedData; var xhr = new XMLHttpRequest(); @@ -603,6 +667,7 @@ function sendDataToServer() { button.classList.add("pure-button-primary"); button.innerHTML = "save"; }, 2000); + showToast('Error while sending timing control data to server.', 'error'); console.log('Error while sending data to server.'); } } @@ -610,3 +675,25 @@ function sendDataToServer() { xhr.send(); loadTCGraphData(); // update the tc data graph } + +function showToast(message, type) { + const toast = document.querySelector('.toast'); + + if (toast) { + toast.textContent = message; + toast.classList.remove('success', 'error'); + + if (type === 'success') { + toast.classList.add('success'); + } else if (type === 'error') { + toast.classList.add('error'); + } + + toast.style.opacity = 1; + + setTimeout(() => { + toast.style.opacity = 0; + }, 5000); + } + } + \ No newline at end of file diff --git a/firmware/html/index_template_top.html b/firmware/html/index_template_top.html index 5d4956f..48515ca 100644 --- a/firmware/html/index_template_top.html +++ b/firmware/html/index_template_top.html @@ -15,6 +15,7 @@

{{LIGHT_NAME}}

+
update @@ -44,7 +45,6 @@
-
diff --git a/firmware/html/style.css b/firmware/html/style.css index 9788312..caa7f53 100644 --- a/firmware/html/style.css +++ b/firmware/html/style.css @@ -43,4 +43,24 @@ background-color: #333; } .top-align { vertical-align: top; +} +.toast { +position: fixed; +bottom: 10px; +left: 50%; +transform: translateX(-50%); +padding: 10px; +border-radius: 5px; +color: #fff; +font-size: 16px; +font-weight: bold; +text-align: center; +opacity: 0; +transition: opacity 0.5s ease-in-out; +} +.toast.success { +background-color: #4CAF50; +} +.toast.error { +background-color: #f44336; } \ No newline at end of file diff --git a/firmware/html/top.js b/firmware/html/top.js index bf4ddaa..0f07a78 100644 --- a/firmware/html/top.js +++ b/firmware/html/top.js @@ -27,6 +27,7 @@ links.forEach(function(link) { button.classList.add("pure-button-primary"); button.innerHTML = "ON"; }, 2000); + showToast('Error while sending data to server.', 'error'); console.log('Error while sending data to server.'); } } @@ -67,6 +68,7 @@ links.forEach(function(link) { button.classList.add("pure-button-primary"); button.innerHTML = "OFF"; }, 2000); + showToast('Error while sending data to server.', 'error'); console.log('Error while sending data to server.'); } } @@ -92,6 +94,7 @@ function sendSliderValue(x) { } //console.log(`Sent slider value ${value} to ${url}`); }).catch(error => { + showToast(`Error sending slider value to ${url}: ${error}`, 'error'); console.error(`Error sending slider value to ${url}: ${error}`); }); }, 500); diff --git a/pic/schematics.png b/pic/schematics.png index f03a73b..b7b75c2 100644 Binary files a/pic/schematics.png and b/pic/schematics.png differ