function addTabListener() { //console.log("Try to add tab listener"); try { var tabMain = document.getElementById("tab-lights"); var tabConfig = document.getElementById("tab-config"); var tabTDE = document.getElementById("tab-tde"); var amain = document.getElementById("tab-a-lights"); var acfg = document.getElementById("tab-a-config"); var atde = document.getElementById("tab-a-tde"); amain.addEventListener("click", function() { //console.log("Switch to main lights tab"); tabMain.classList.add("visible"); tabConfig.classList.remove("visible"); tabTDE.classList.remove("visible"); amain.classList.add("pure-button-primary"); acfg.classList.remove("pure-button-primary"); atde.classList.remove("pure-button-primary"); loadGraphData(); // reload the graph }); acfg.addEventListener("click", function() { //console.log("Switch to config tab"); tabMain.classList.remove("visible"); tabConfig.classList.add("visible"); tabTDE.classList.remove("visible"); amain.classList.remove("pure-button-primary"); acfg.classList.add("pure-button-primary"); atde.classList.remove("pure-button-primary"); }); atde.addEventListener("click", function() { //console.log("Switch to TDE tab"); tabMain.classList.remove("visible"); tabConfig.classList.remove("visible"); tabTDE.classList.add("visible"); amain.classList.remove("pure-button-primary"); acfg.classList.remove("pure-button-primary"); atde.classList.add("pure-button-primary"); createTable(); // recreate the table on timing data editor tab fillTableFromJson(); }); } catch (error) { console.log("Error: load listener of the tab action listener management: " + error.message); } } window.addEventListener('load', function() { addTabListener(); }); function loadGraphData() { console.log('----> generate graph <----'); $.getJSON('/tc_data_blocks_read', function(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('plot_chart', [trace1, trace2, trace3, trace4], layout); }); } setInterval(loadGraphData, 10000); 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() { console.log('----> setting bri and power switch <----'); for (let i = 1; i <= {{LIGHT_COUNT}}; i++) { 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`); const onLinkOn = document.getElementById(`on${i - 1}_on`); const onLinkOff = document.getElementById(`on${i - 1}_off`); briSlider.value = data.bri; briSliderVal.innerHTML = (Math.round((data.bri * 100.0 / 255.0) * 100) / 100).toFixed(2); //console.log('data.on ' + i + ' = ' + data.on); if (data.on == true) { onLinkOn.classList.add('pure-button-primary'); onLinkOff.classList.remove('pure-button-primary'); } else { onLinkOn.classList.remove('pure-button-primary'); onLinkOff.classList.add('pure-button-primary'); } }).catch(error => console.error(error)); } } setInterval(updateLightState, 10000); updateLightState(); function updatePWMValues() { console.log('----> setting pwm data <----'); 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`); if (pwmElement) { 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)); //console.log('curpwm[' + i + '] = ' + data.curpwm + ' = ' + pwmValue); pwmElement.innerText = pwmValue.toString(); pwmElement.value = pwmValue; pwmElementTxt.innerText = pwmValue.toString(); }).catch(error => console.error(error)); } } } updatePWMValues(); setInterval(updatePWMValues, 5000); // Suche nach allen Links auf der Seite mit IDs von on0_off bis on3_off var links = document.querySelectorAll('[id^="on"][id$="_off"]'); // Füge einen Klick-Listener zu jedem Link hinzu links.forEach(function(link) { link.addEventListener('click', function(event) { // Verhindere, dass der Link die Seite neu lädt 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 var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=false&transition=' + document.getElementById('transition').value, true); // Sende die Anfrage im Hintergrund xhr.send(); updateLightState(); this.classList.add('pure-button-primary'); document.getElementById('on'+id+'_on').classList.remove('pure-button-primary'); }); }); // Suche nach allen Links auf der Seite mit IDs von on0_off bis on3_off var links = document.querySelectorAll('[id^="on"][id$="_on"]'); // Füge einen Klick-Listener zu jedem Link hinzu links.forEach(function(link) { link.addEventListener('click', function(event) { // Verhindere, dass der Link die Seite neu lädt event.preventDefault(); // Extrahiere die Zahl aus der ID des Links var id = this.id.replace('on', '').replace('_on', ''); // Erstelle eine neue Anfrage an die entsprechende URL var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://{{IP_ADDRESS}}/?on' + id + '=true&transition=' + document.getElementById('transition').value, true); // Sende die Anfrage im Hintergrund xhr.send(); updateLightState(); this.classList.add('pure-button-primary'); document.getElementById('on'+id+'_off').classList.remove('pure-button-primary'); }); }); function createTable() { // Erstelle eine Tabelle var table = document.createElement("table"); table.border = "1"; // Erstelle eine Kopfzeile var headerRow = document.createElement("tr"); // Füge die Spaltenüberschriften hinzu var headers = ["Hour", "Minute", "Ch1", "Ch2", "Ch3", "Ch4"]; headers.forEach(header => { var th = document.createElement("th"); th.innerHTML = header; headerRow.appendChild(th); }); table.appendChild(headerRow); // Erstelle Zeilen mit Zellen für jedes Element for (var i = 1; i <= 10; i++) { var tr = document.createElement("tr"); // Stunde var tdHour = createSelectCell(23, 0, 1); tdHour.id = "hour" + i; tr.appendChild(tdHour); // Minute var tdMinute = createSelectCell(59, 0, 1); 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); table.appendChild(tr); } var container = document.getElementById("table-container"); container.innerHTML = ""; container.classList.add("pure-form"); container.appendChild(table); } function createSelectCell(max, value, step) { // Erstelle ein neues select-Element var select = document.createElement("select"); // Füge Optionen hinzu for (var i = 0; i <= max; i += step) { var option = document.createElement("option"); option.value = i; option.text = i; select.appendChild(option); } // Wähle die Option aus, die dem übergebenen Wert entspricht select.value = value; // Erstelle eine neue Zellenreihe und -zelle var row = document.createElement("td"); row.appendChild(select); // Gib die Zelle zurück return row; } function fillTableFromJson() { // Lade JSON-Daten fetch('http://{{IP_ADDRESS}}/tc_data_blocks_read') .then(response => response.json()) .then(data => { // Fülle die Tabelle mit Daten var tcdata = data.tcdata; 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)); } loadTCGraphData(); }); } function createJsonFromTable() { var tableRows = document.querySelectorAll("table tr"); var tcdata = []; 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 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; var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); 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(); // update the tc data graph }