Compare commits
3 commits
94e1e703e3
...
99c0c4a6b5
Author | SHA1 | Date | |
---|---|---|---|
|
99c0c4a6b5 | ||
|
2f7ce5019b | ||
|
94a347d3d0 |
16 changed files with 911 additions and 1099 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
.DS_store
|
||||
.vscode/c_cpp_properties.json
|
||||
|
|
289
firmware/data/bottom.js
Normal file
289
firmware/data/bottom.js
Normal file
|
@ -0,0 +1,289 @@
|
|||
function addTabListener() {
|
||||
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() {
|
||||
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");
|
||||
});
|
||||
acfg.addEventListener("click", function() {
|
||||
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() {
|
||||
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();
|
||||
});
|
||||
} 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']);
|
||||
channel2.push(data['tcdata'][i]['ch2']);
|
||||
channel3.push(data['tcdata'][i]['ch3']);
|
||||
channel4.push(data['tcdata'][i]['ch4']);
|
||||
}
|
||||
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, 255],
|
||||
},
|
||||
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 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);
|
||||
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));
|
||||
pwmElement.innerText = pwmValue.toString();
|
||||
pwmElement.value = pwmValue;
|
||||
pwmElementTxt.innerText = pwmValue.toString();
|
||||
}).catch(error => console.error(error));
|
||||
}
|
||||
}
|
||||
}
|
||||
updatePWMValues();
|
||||
setInterval(updatePWMValues, 5000);
|
||||
var links = document.querySelectorAll('[id^="on"][id$="_off"]');
|
||||
links.forEach(function(link) {
|
||||
link.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
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.send();
|
||||
updateLightState();
|
||||
this.classList.add('pure-button-primary');
|
||||
document.getElementById('on'+id+'_on').classList.remove('pure-button-primary');
|
||||
});
|
||||
});
|
||||
var links = document.querySelectorAll('[id^="on"][id$="_on"]');
|
||||
links.forEach(function(link) {
|
||||
link.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
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();
|
||||
updateLightState();
|
||||
this.classList.add('pure-button-primary');
|
||||
document.getElementById('on'+id+'_off').classList.remove('pure-button-primary');
|
||||
});
|
||||
});
|
||||
function createTable() {
|
||||
var table = document.createElement("table");
|
||||
var headerRow = document.createElement("tr");
|
||||
var headers = ["Stunde", "Minute", "ch1", "ch2", "ch3", "ch4"];
|
||||
for (var i = 0; i < headers.length; i++) {
|
||||
var header = document.createElement("th");
|
||||
header.innerHTML = headers[i];
|
||||
headerRow.appendChild(header);
|
||||
}
|
||||
table.appendChild(headerRow);
|
||||
for (var row = 0; row < 10; row++) {
|
||||
var contentRow = document.createElement("tr");
|
||||
var hourCell = document.createElement("td");
|
||||
var hourInput = document.createElement("input");
|
||||
hourInput.type = "number";
|
||||
hourInput.min = 0;
|
||||
hourInput.max = 23;
|
||||
hourCell.appendChild(hourInput);
|
||||
contentRow.appendChild(hourCell);
|
||||
var minuteCell = document.createElement("td");
|
||||
var minuteSelect = document.createElement("select");
|
||||
for (var minute = 0; minute <= 50; minute += 10) {
|
||||
var option = document.createElement("option");
|
||||
option.value = minute;
|
||||
option.text = minute.toString().padStart(2, "0");
|
||||
minuteSelect.appendChild(option);
|
||||
}
|
||||
minuteCell.appendChild(minuteSelect);
|
||||
contentRow.appendChild(minuteCell);
|
||||
for (var channel = 1; channel <= 4; channel++) {
|
||||
var channelCell = document.createElement("td");
|
||||
var channelInput = document.createElement("input");
|
||||
channelInput.type = "number";
|
||||
channelInput.min = 0;
|
||||
channelInput.max = 100;
|
||||
channelCell.appendChild(channelInput);
|
||||
contentRow.appendChild(channelCell);
|
||||
}
|
||||
table.appendChild(contentRow);
|
||||
}
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Save";
|
||||
button.classList.add("pure-button");
|
||||
button.classList.add("pure-button-primary");
|
||||
button.onclick = function() {
|
||||
var data = [];
|
||||
var rows = table.getElementsByTagName("tr");
|
||||
for (var row = 1; row < rows.length; row++) {
|
||||
var cells = rows[row].getElementsByTagName("td");
|
||||
var hour = cells[0].querySelector("input").value;
|
||||
var minute = cells[1].querySelector("select").value;
|
||||
var ch1 = cells[2].querySelector("input").value;
|
||||
var ch2 = cells[3].querySelector("input").value;
|
||||
var ch3 = cells[4].querySelector("input").value;
|
||||
var ch4 = cells[5].querySelector("input").value;
|
||||
var rowObject = {"hour": hour, "min": minute, "ch1": ch1, "ch2": ch2, "ch3": ch3, "ch4": ch4};
|
||||
data.push(rowObject);
|
||||
}
|
||||
var json = JSON.stringify(data);
|
||||
console.log(json);
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "http://{{IP_ADDRESS}}/tc_data_save?data=" + encodeURIComponent(json), true);
|
||||
xhr.send();
|
||||
};
|
||||
var container = document.getElementById("table-container");
|
||||
container.innerHTML = "";
|
||||
container.classList.add("pure-form");
|
||||
container.appendChild(table);
|
||||
container.appendChild(button);
|
||||
}
|
|
@ -1,249 +1,14 @@
|
|||
<!-- bottom -->
|
||||
<div id="tab-tde" class=""> <!-- timing editor -->
|
||||
<div id="tc-edit-container" class=""></div>
|
||||
<div id="tc-edit-container" class="">
|
||||
<br>
|
||||
<label>
|
||||
<strong>Timming control data editor</strong>
|
||||
</label>
|
||||
<div id="table-container"></div>
|
||||
</div>
|
||||
</div> <!-- end of tab-tde -->
|
||||
<script>
|
||||
function addTabListener() {
|
||||
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() {
|
||||
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");
|
||||
});
|
||||
acfg.addEventListener("click", function() {
|
||||
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() {
|
||||
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");
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Fehler in 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']);
|
||||
channel2.push(data['tcdata'][i]['ch2']);
|
||||
channel3.push(data['tcdata'][i]['ch3']);
|
||||
channel4.push(data['tcdata'][i]['ch4']);
|
||||
}
|
||||
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.");
|
||||
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, 255],
|
||||
},
|
||||
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 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);
|
||||
var links = document.querySelectorAll('[id^="on"][id$="_off"]');
|
||||
links.forEach(function(link) {
|
||||
link.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
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.send();
|
||||
updateLightState();
|
||||
this.classList.add('pure-button-primary');
|
||||
document.getElementById('on'+id+'_on').classList.remove('pure-button-primary');
|
||||
});
|
||||
});
|
||||
var links = document.querySelectorAll('[id^="on"][id$="_on"]');
|
||||
links.forEach(function(link) {
|
||||
link.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
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();
|
||||
updateLightState();
|
||||
this.classList.add('pure-button-primary');
|
||||
document.getElementById('on'+id+'_off').classList.remove('pure-button-primary');
|
||||
});
|
||||
});
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'http://{{IP_ADDRESS}}/tc_data_edit');
|
||||
xhr.onload = function() {
|
||||
if (xhr.status === 200) {
|
||||
document.getElementById('tc-edit-container').innerHTML = xhr.responseText;
|
||||
} else {
|
||||
console.log('Fehler beim Laden der URL: ' + xhr.status);
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
<script src="http://{{IP_ADDRESS}}/js_bottom">
|
||||
</script>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
|
|
@ -9,22 +9,7 @@
|
|||
<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">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
#tab-lights, #tab-config, #tab-tde {
|
||||
display: none;
|
||||
background-color: #ffffff;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
#tab-lights.visible {
|
||||
display: block;
|
||||
}
|
||||
#tab-config.visible {
|
||||
display: block;
|
||||
}
|
||||
#tab-tde.visible {
|
||||
display: block;
|
||||
}
|
||||
<style src="http://{{IP_ADDRESS}}'/css">
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -57,48 +42,7 @@ display: block;
|
|||
<input id="transition" name="transition" type="text" placeholder="10" value="{{TRANSITION_TIME}}">
|
||||
</div>
|
||||
<br>
|
||||
<script>
|
||||
var links = document.querySelectorAll('[id^="tc_on"]');
|
||||
links.forEach(function(link) {
|
||||
link.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'http://{{IP_ADDRESS}}/?tc=true', true);
|
||||
xhr.send();
|
||||
console.log('tc=true call');
|
||||
document.getElementById('tc_on').classList.add('pure-button-primary');
|
||||
document.getElementById('tc_off').classList.remove('pure-button-primary');
|
||||
});
|
||||
});
|
||||
var links = document.querySelectorAll('[id^="tc_off"]');
|
||||
links.forEach(function(link) {
|
||||
link.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'http://{{IP_ADDRESS}}/?tc=false', true);
|
||||
xhr.send();
|
||||
console.log('tc=false call');
|
||||
document.getElementById('tc_off').classList.add('pure-button-primary');
|
||||
document.getElementById('tc_on').classList.remove('pure-button-primary');
|
||||
});
|
||||
});
|
||||
let timeoutId;
|
||||
function sendSliderValue(x) {
|
||||
x = x - 1;
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(() => {
|
||||
var value = document.getElementById(`bri${x}`).value;
|
||||
var url = `http://{{IP_ADDRESS}}/?bri${x}=${value}`;
|
||||
fetch(url).then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
console.log(`Sent slider value ${value} to ${url}`);
|
||||
}).catch(error => {
|
||||
console.error(`Error sending slider value to ${url}: ${error}`);
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
<script src="http://{{IP_ADDRESS}}/js_top">
|
||||
</script>
|
||||
<br>
|
||||
<table border=0>
|
||||
|
|
52
firmware/data/style.css
Normal file
52
firmware/data/style.css
Normal file
|
@ -0,0 +1,52 @@
|
|||
#tab-lights, #tab-config, #tab-tde {
|
||||
display: none;
|
||||
background-color: #ffffff;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
#tab-lights.visible {
|
||||
display: block;
|
||||
}
|
||||
#tab-config.visible {
|
||||
display: block;
|
||||
}
|
||||
#tab-tde.visible {
|
||||
display: block;
|
||||
}
|
||||
/* CSS-Regeln für die Tabellenzellen */
|
||||
.pure-table td {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
/* CSS-Regeln für die Eingabefelder */
|
||||
.pure-form input[type="number"] {
|
||||
width: 60px;
|
||||
height: 20px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
/* CSS-Regeln für die Auswahllisten */
|
||||
.pure-form select {
|
||||
width: 80px;
|
||||
height: 26px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/* CSS-Regeln für den Export-Button */
|
||||
.pure-button {
|
||||
background-color: #5a5a5a;
|
||||
color: #fff;
|
||||
border-radius: 3px;
|
||||
border: none;
|
||||
padding: 8px 12px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pure-button:hover {
|
||||
background-color: #333;
|
||||
}
|
||||
|
|
@ -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>
|
38
firmware/data/top.js
Normal file
38
firmware/data/top.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
var links = document.querySelectorAll('[id^="tc_on"]');
|
||||
links.forEach(function(link) {
|
||||
link.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'http://{{IP_ADDRESS}}/?tc=true', true);
|
||||
xhr.send();
|
||||
document.getElementById('tc_on').classList.add('pure-button-primary');
|
||||
document.getElementById('tc_off').classList.remove('pure-button-primary');
|
||||
});
|
||||
});
|
||||
var links = document.querySelectorAll('[id^="tc_off"]');
|
||||
links.forEach(function(link) {
|
||||
link.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'http://{{IP_ADDRESS}}/?tc=false', true);
|
||||
xhr.send();
|
||||
document.getElementById('tc_off').classList.add('pure-button-primary');
|
||||
document.getElementById('tc_on').classList.remove('pure-button-primary');
|
||||
});
|
||||
});
|
||||
let timeoutId;
|
||||
function sendSliderValue(x) {
|
||||
x = x - 1;
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(() => {
|
||||
var value = document.getElementById(`bri${x}`).value;
|
||||
var url = `http://{{IP_ADDRESS}}/?bri${x}=${value}`;
|
||||
fetch(url).then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error(`Error sending slider value to ${url}: ${error}`);
|
||||
});
|
||||
}, 500);
|
||||
}
|
|
@ -489,9 +489,19 @@ void init_webserver()
|
|||
}
|
||||
});
|
||||
|
||||
server.on("/tc_data_edit", []()
|
||||
server.on("/js_top", []()
|
||||
{
|
||||
server.send(200, "text/html", genTCEditHTML());
|
||||
server.send(200, "text/html", replacePlaceholder(loadSPIFFSFile("/top.js")));
|
||||
});
|
||||
|
||||
server.on("/js_bottom", []()
|
||||
{
|
||||
server.send(200, "text/html", replacePlaceholder(loadSPIFFSFile("/bottom.js")));
|
||||
});
|
||||
|
||||
server.on("/css", []()
|
||||
{
|
||||
server.send(200, "text/html", loadSPIFFSFile("/style.css"));
|
||||
});
|
||||
|
||||
server.on("/", []()
|
||||
|
|
347
firmware/html/bottom.js
Normal file
347
firmware/html/bottom.js
Normal file
|
@ -0,0 +1,347 @@
|
|||
function addTabListener() {
|
||||
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() {
|
||||
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");
|
||||
});
|
||||
|
||||
acfg.addEventListener("click", function() {
|
||||
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() {
|
||||
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();
|
||||
});
|
||||
} 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']);
|
||||
channel2.push(data['tcdata'][i]['ch2']);
|
||||
channel3.push(data['tcdata'][i]['ch3']);
|
||||
channel4.push(data['tcdata'][i]['ch4']);
|
||||
}
|
||||
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, 255],
|
||||
},
|
||||
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 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() {
|
||||
var table = document.createElement("table");
|
||||
|
||||
// Headerzeile
|
||||
var headerRow = document.createElement("tr");
|
||||
var headers = ["Stunde", "Minute", "ch1", "ch2", "ch3", "ch4"];
|
||||
for (var i = 0; i < headers.length; i++) {
|
||||
var header = document.createElement("th");
|
||||
header.innerHTML = headers[i];
|
||||
headerRow.appendChild(header);
|
||||
}
|
||||
table.appendChild(headerRow);
|
||||
|
||||
// Inhaltszeilen
|
||||
for (var row = 0; row < 10; row++) {
|
||||
var contentRow = document.createElement("tr");
|
||||
|
||||
// Spalte "Stunde"
|
||||
var hourCell = document.createElement("td");
|
||||
var hourInput = document.createElement("input");
|
||||
hourInput.type = "number";
|
||||
hourInput.min = 0;
|
||||
hourInput.max = 23;
|
||||
hourCell.appendChild(hourInput);
|
||||
contentRow.appendChild(hourCell);
|
||||
|
||||
// Spalte "Minute"
|
||||
var minuteCell = document.createElement("td");
|
||||
var minuteSelect = document.createElement("select");
|
||||
for (var minute = 0; minute <= 50; minute += 10) {
|
||||
var option = document.createElement("option");
|
||||
option.value = minute;
|
||||
option.text = minute.toString().padStart(2, "0");
|
||||
minuteSelect.appendChild(option);
|
||||
}
|
||||
minuteCell.appendChild(minuteSelect);
|
||||
contentRow.appendChild(minuteCell);
|
||||
|
||||
// Spalten "ch1" bis "ch4"
|
||||
for (var channel = 1; channel <= 4; channel++) {
|
||||
var channelCell = document.createElement("td");
|
||||
var channelInput = document.createElement("input");
|
||||
channelInput.type = "number";
|
||||
channelInput.min = 0;
|
||||
channelInput.max = 100;
|
||||
channelCell.appendChild(channelInput);
|
||||
contentRow.appendChild(channelCell);
|
||||
}
|
||||
|
||||
table.appendChild(contentRow);
|
||||
}
|
||||
|
||||
// Button
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Save";
|
||||
button.classList.add("pure-button");
|
||||
button.classList.add("pure-button-primary");
|
||||
button.onclick = function() {
|
||||
var data = [];
|
||||
|
||||
var rows = table.getElementsByTagName("tr");
|
||||
for (var row = 1; row < rows.length; row++) {
|
||||
var cells = rows[row].getElementsByTagName("td");
|
||||
|
||||
var hour = cells[0].querySelector("input").value;
|
||||
var minute = cells[1].querySelector("select").value;
|
||||
var ch1 = cells[2].querySelector("input").value;
|
||||
var ch2 = cells[3].querySelector("input").value;
|
||||
var ch3 = cells[4].querySelector("input").value;
|
||||
var ch4 = cells[5].querySelector("input").value;
|
||||
|
||||
var rowObject = {"hour": hour, "min": minute, "ch1": ch1, "ch2": ch2, "ch3": ch3, "ch4": ch4};
|
||||
data.push(rowObject);
|
||||
}
|
||||
|
||||
var json = JSON.stringify(data);
|
||||
console.log(json);
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "http://{{IP_ADDRESS}}/tc_data_save?data=" + encodeURIComponent(json), true);
|
||||
xhr.send();
|
||||
|
||||
};
|
||||
|
||||
var container = document.getElementById("table-container");
|
||||
container.innerHTML = "";
|
||||
container.classList.add("pure-form");
|
||||
container.appendChild(table);
|
||||
container.appendChild(button);
|
||||
}
|
|
@ -1,283 +1,15 @@
|
|||
<!-- bottom -->
|
||||
<div id="tab-tde" class=""> <!-- timing editor -->
|
||||
<div id="tc-edit-container" class=""></div>
|
||||
<div id="tc-edit-container" class="">
|
||||
<br>
|
||||
<label>
|
||||
<strong>Timming control data editor</strong>
|
||||
</label>
|
||||
<div id="table-container"></div>
|
||||
</div>
|
||||
</div> <!-- end of tab-tde -->
|
||||
|
||||
<script>
|
||||
function addTabListener() {
|
||||
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() {
|
||||
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");
|
||||
});
|
||||
|
||||
acfg.addEventListener("click", function() {
|
||||
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() {
|
||||
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");
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Fehler in 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']);
|
||||
channel2.push(data['tcdata'][i]['ch2']);
|
||||
channel3.push(data['tcdata'][i]['ch3']);
|
||||
channel4.push(data['tcdata'][i]['ch4']);
|
||||
}
|
||||
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.");
|
||||
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, 255],
|
||||
},
|
||||
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 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');
|
||||
});
|
||||
});
|
||||
|
||||
// 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 src="http://{{IP_ADDRESS}}/js_bottom">
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -1,108 +1,51 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Light setup - {{LIGHT_NAME}}</title>
|
||||
<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://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">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
#tab-lights, #tab-config, #tab-tde {
|
||||
display: none;
|
||||
background-color: #ffffff;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
#tab-lights.visible {
|
||||
display: block;
|
||||
}
|
||||
#tab-config.visible {
|
||||
display: block;
|
||||
}
|
||||
#tab-tde.visible {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<fieldset>
|
||||
<h3>{{LIGHT_NAME}}</h3>
|
||||
<div class="pure-form pure-form-aligned">
|
||||
<div class="pure-controls">
|
||||
<a href="/update" class="pure-button">update</a>
|
||||
<a href="/?reset=1" class="pure-button">reset light</a>
|
||||
<a href="/?resettc" class="pure-button">reset timing control data</a>
|
||||
<a href="/?alert=1" class="pure-button">alert</a>
|
||||
</div>
|
||||
<br>
|
||||
<div><!-- Tab links -->
|
||||
<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-tde" class="pure-button">Timing data edit</a>
|
||||
</div>
|
||||
<br>
|
||||
<div id="tab-lights" class="visible"> <!-- lights control tab -->
|
||||
<br>
|
||||
<div class="pure-control-group">
|
||||
<label for="tc_on">
|
||||
<strong>Timing control</strong>
|
||||
</label>
|
||||
<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>
|
||||
<br>
|
||||
<label for="transition">Transition time (s)</label>
|
||||
<input id="transition" name="transition" type="text" placeholder="10" value="{{TRANSITION_TIME}}">
|
||||
</div>
|
||||
<br>
|
||||
<script>
|
||||
var links = document.querySelectorAll('[id^="tc_on"]');
|
||||
links.forEach(function(link) {
|
||||
link.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'http://{{IP_ADDRESS}}/?tc=true', true);
|
||||
xhr.send();
|
||||
console.log('tc=true call');
|
||||
document.getElementById('tc_on').classList.add('pure-button-primary');
|
||||
document.getElementById('tc_off').classList.remove('pure-button-primary');
|
||||
});
|
||||
});
|
||||
var links = document.querySelectorAll('[id^="tc_off"]');
|
||||
links.forEach(function(link) {
|
||||
link.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'http://{{IP_ADDRESS}}/?tc=false', true);
|
||||
xhr.send();
|
||||
console.log('tc=false call');
|
||||
document.getElementById('tc_off').classList.add('pure-button-primary');
|
||||
document.getElementById('tc_on').classList.remove('pure-button-primary');
|
||||
});
|
||||
});
|
||||
|
||||
let timeoutId;
|
||||
function sendSliderValue(x) {
|
||||
x = x - 1;
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(() => {
|
||||
var value = document.getElementById(`bri${x}`).value;
|
||||
var url = `http://{{IP_ADDRESS}}/?bri${x}=${value}`;
|
||||
fetch(url).then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
console.log(`Sent slider value ${value} to ${url}`);
|
||||
}).catch(error => {
|
||||
console.error(`Error sending slider value to ${url}: ${error}`);
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
</script>
|
||||
<br>
|
||||
<table border=0>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Light setup - {{LIGHT_NAME}}</title>
|
||||
<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://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">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style src="http://{{IP_ADDRESS}}'/css">
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<fieldset>
|
||||
<h3>{{LIGHT_NAME}}</h3>
|
||||
<div class="pure-form pure-form-aligned">
|
||||
<div class="pure-controls">
|
||||
<a href="/update" class="pure-button">update</a>
|
||||
<a href="/?reset=1" class="pure-button">reset light</a>
|
||||
<a href="/?resettc" class="pure-button">reset timing control data</a>
|
||||
<a href="/?alert=1" class="pure-button">alert</a>
|
||||
</div>
|
||||
<br>
|
||||
<div><!-- Tab links -->
|
||||
<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-tde" class="pure-button">Timing data edit</a>
|
||||
</div>
|
||||
<br>
|
||||
<div id="tab-lights" class="visible"> <!-- lights control tab -->
|
||||
<br>
|
||||
<div class="pure-control-group">
|
||||
<label for="tc_on">
|
||||
<strong>Timing control</strong>
|
||||
</label>
|
||||
<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>
|
||||
<br>
|
||||
<label for="transition">Transition time (s)</label>
|
||||
<input id="transition" name="transition" type="text" placeholder="10" value="{{TRANSITION_TIME}}">
|
||||
</div>
|
||||
<br>
|
||||
<script src="http://{{IP_ADDRESS}}/js_top">
|
||||
</script>
|
||||
<br>
|
||||
<table border=0>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
|
|
52
firmware/html/style.css
Normal file
52
firmware/html/style.css
Normal file
|
@ -0,0 +1,52 @@
|
|||
#tab-lights, #tab-config, #tab-tde {
|
||||
display: none;
|
||||
background-color: #ffffff;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
#tab-lights.visible {
|
||||
display: block;
|
||||
}
|
||||
#tab-config.visible {
|
||||
display: block;
|
||||
}
|
||||
#tab-tde.visible {
|
||||
display: block;
|
||||
}
|
||||
/* CSS-Regeln für die Tabellenzellen */
|
||||
.pure-table td {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
/* CSS-Regeln für die Eingabefelder */
|
||||
.pure-form input[type="number"] {
|
||||
width: 60px;
|
||||
height: 20px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
/* CSS-Regeln für die Auswahllisten */
|
||||
.pure-form select {
|
||||
width: 80px;
|
||||
height: 26px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/* CSS-Regeln für den Export-Button */
|
||||
.pure-button {
|
||||
background-color: #5a5a5a;
|
||||
color: #fff;
|
||||
border-radius: 3px;
|
||||
border: none;
|
||||
padding: 8px 12px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pure-button:hover {
|
||||
background-color: #333;
|
||||
}
|
||||
|
|
@ -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>
|
42
firmware/html/top.js
Normal file
42
firmware/html/top.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
var links = document.querySelectorAll('[id^="tc_on"]');
|
||||
links.forEach(function(link) {
|
||||
link.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'http://{{IP_ADDRESS}}/?tc=true', true);
|
||||
xhr.send();
|
||||
//console.log('tc=true call');
|
||||
document.getElementById('tc_on').classList.add('pure-button-primary');
|
||||
document.getElementById('tc_off').classList.remove('pure-button-primary');
|
||||
});
|
||||
});
|
||||
var links = document.querySelectorAll('[id^="tc_off"]');
|
||||
links.forEach(function(link) {
|
||||
link.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'http://{{IP_ADDRESS}}/?tc=false', true);
|
||||
xhr.send();
|
||||
//console.log('tc=false call');
|
||||
document.getElementById('tc_off').classList.add('pure-button-primary');
|
||||
document.getElementById('tc_on').classList.remove('pure-button-primary');
|
||||
});
|
||||
});
|
||||
|
||||
let timeoutId;
|
||||
function sendSliderValue(x) {
|
||||
x = x - 1;
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(() => {
|
||||
var value = document.getElementById(`bri${x}`).value;
|
||||
var url = `http://{{IP_ADDRESS}}/?bri${x}=${value}`;
|
||||
fetch(url).then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
//console.log(`Sent slider value ${value} to ${url}`);
|
||||
}).catch(error => {
|
||||
console.error(`Error sending slider value to ${url}: ${error}`);
|
||||
});
|
||||
}, 500);
|
||||
}
|
|
@ -180,6 +180,12 @@ void tc_update_main()
|
|||
|
||||
if (target_data_block >= NUMBER_OF_TIMER_DATA_BLOCKS)
|
||||
{
|
||||
// we are not between two valid data points, do nothing
|
||||
// TODO check if setting all lights to false is correct here
|
||||
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
|
||||
{
|
||||
light_state[i] = false;
|
||||
}
|
||||
target_data_block = 255;
|
||||
current_target_data_block = 255;
|
||||
return;
|
||||
|
|
|
@ -5,4 +5,6 @@ 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/config_template.html > config_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
|
||||
bash ../../tools/html2string.sh ../html/top.js > top.js
|
||||
bash ../../tools/html2string.sh ../html/bottom.js > bottom.js
|
||||
cp -av ../html/style.css .
|
||||
|
|
Loading…
Reference in a new issue