2023-05-01 19:23:31 +02:00
|
|
|
|
|
|
|
String getIndexHTML()
|
|
|
|
{
|
|
|
|
String index_html = ""
|
|
|
|
"<!doctype html>"
|
|
|
|
"<html>"
|
|
|
|
"<head>"
|
|
|
|
"<style></style>"
|
|
|
|
"<meta charset=\"utf-8\">"
|
|
|
|
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
|
|
|
"<title>Light setup</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\">"
|
|
|
|
"</head>"
|
|
|
|
"<body>"
|
|
|
|
"<fieldset>"
|
|
|
|
"<h3>{{LIGHT_NAME}}</h3>"
|
|
|
|
"<div class=\"pure-form pure-form-aligned\">"
|
|
|
|
"<div class=\"pure-controls\">"
|
|
|
|
"<span class=\"pure-form-message\">"
|
|
|
|
"<a href=\"/?alert=1\">alert</a>"
|
|
|
|
" "
|
|
|
|
"<a href=\"/?reset=1\">reset</a>"
|
|
|
|
" "
|
|
|
|
"<a href=\"/?resettc\">reset timing control data</a>"
|
|
|
|
" "
|
|
|
|
"<a href=\"/update\">update</a>"
|
|
|
|
"</span>"
|
|
|
|
"<label for=\"cb\" class=\"pure-checkbox\"></label>"
|
|
|
|
"</div>"
|
|
|
|
"<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>"
|
|
|
|
"</div>"
|
|
|
|
"<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');"
|
|
|
|
"});"
|
|
|
|
"});"
|
|
|
|
"</script>"
|
|
|
|
"<br>"
|
|
|
|
"<div class=\"pure-control-group\">"
|
|
|
|
"<label for=\"transition\">Transition time (s)</label>"
|
|
|
|
"<input id=\"transition\" name=\"transition\" type=\"text\" placeholder=\"10\" value=\"{{TRANSITION_TIME}}\">"
|
|
|
|
"</div>"
|
|
|
|
"<br>"
|
|
|
|
"<script>"
|
|
|
|
"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>"
|
|
|
|
"{{LIGHTS_CONTROL}}"
|
|
|
|
""
|
|
|
|
"</td>"
|
|
|
|
"<td>"
|
|
|
|
"<div id=\"plot_chart\"></div>"
|
|
|
|
"</td>"
|
|
|
|
"</tr>"
|
|
|
|
"</table>"
|
|
|
|
"{{CONFIG_PAGE}}"
|
|
|
|
"<script>"
|
|
|
|
"function loadGraphData() {"
|
|
|
|
"console.log('----> generate graph <----');"
|
|
|
|
"$.getJSON('/tc_data_blocks', 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_NUM}}; 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_NUM}}; 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);"
|
|
|
|
"</script>"
|
|
|
|
"</div>"
|
|
|
|
"</fieldset>"
|
|
|
|
"</body>"
|
|
|
|
"</html>";
|
|
|
|
return index_html;
|
|
|
|
}
|