First working version with the new html page generation out of SPIFFS files.
This commit is contained in:
parent
55821b8282
commit
c973cf0ed0
17 changed files with 706 additions and 574 deletions
|
@ -1,66 +0,0 @@
|
||||||
|
|
||||||
String getConfigHTML()
|
|
||||||
{
|
|
||||||
String config_html = "<form class=\"pure-form pure-form-aligned\" action=\"/\" method=\"post\">"
|
|
||||||
"<h3>Config</h3>"
|
|
||||||
"<div class=\"pure-control-group\">"
|
|
||||||
"<label for=\"startup\">"
|
|
||||||
"<strong>Startup</strong>"
|
|
||||||
"</label>"
|
|
||||||
"<select onchange=\"this.form.submit()\" id=\"startup\" name=\"startup\">"
|
|
||||||
"<option {{STARTUP_SELECTED_LS_0}} value=\"0\">Last state</option>"
|
|
||||||
"<option {{STARTUP_SELECTED_ON_1}} value=\"1\">On</option>"
|
|
||||||
"<option {{STARTUP_SELECTED_OFF_2}} value=\"2\">Off</option>"
|
|
||||||
"</select>"
|
|
||||||
"</div>"
|
|
||||||
"<div class=\"pure-control-group\">"
|
|
||||||
"<label for=\"scene\">"
|
|
||||||
"<strong>Scene</strong>"
|
|
||||||
"</label>"
|
|
||||||
"<select onchange=\"this.form.submit()\" id=\"scene\" name=\"scene\">"
|
|
||||||
"<option {{SCENE_SELECTED_RELAX_0}} value=\"0\">Relax</option>"
|
|
||||||
"<option {{SCENE_SELECTED_BRIGHT_1}} value=\"1\">Bright</option>"
|
|
||||||
"<option {{SCENE_SELECTED_NIGHT_2}} value=\"2\">Night</option>"
|
|
||||||
"</select>"
|
|
||||||
"</div>"
|
|
||||||
"<br>"
|
|
||||||
"<h3>Wifi</h3>"
|
|
||||||
"<div class=\"pure-control-group\">"
|
|
||||||
"<label for=\"ip\">SSID</label>"
|
|
||||||
"<input id=\"ssid\" name=\"ssid\" type=\"text\" value=\"{{WIFI_SSID}}\">"
|
|
||||||
"</div>"
|
|
||||||
"<div class=\"pure-control-group\">"
|
|
||||||
"<label for=\"wpw\">Passphrase</label>"
|
|
||||||
"<input id=\"wpw\" name=\"wpw\" type=\"text\" placeholder=\"1234password\">"
|
|
||||||
"</div>"
|
|
||||||
"<br>"
|
|
||||||
"<h3>Network</h3>"
|
|
||||||
"<div class=\"pure-control-group\">"
|
|
||||||
"<label for=\"dip\">"
|
|
||||||
"<strong>Dynamic-IP</strong>"
|
|
||||||
"</label>"
|
|
||||||
"<a class=\"pure-button {{DIP_LINK_ON_PRIMARY}}\" href=\"/?dip=true\">ON</a>"
|
|
||||||
"<a class=\"pure-button {{DIP_LINK_OFF_PRIMARY}}\" href=\"/?dip=false\">OFF</a>"
|
|
||||||
"</div>"
|
|
||||||
"<div class=\"pure-control-group\">"
|
|
||||||
"<label for=\"ip\">IP</label>"
|
|
||||||
"<input id=\"ip\" name=\"ip\" type=\"text\" value=\"{{WIFI_CFG_IP}}\">"
|
|
||||||
"</div>"
|
|
||||||
"<div class=\"pure-control-group\">"
|
|
||||||
"<label for=\"gwip\">Gateway IP</label>"
|
|
||||||
"<input id=\"gwip\" name=\"gwip\" type=\"text\" value=\"{{WIFI_CFG_GW}}\">"
|
|
||||||
"</div>"
|
|
||||||
"<div class=\"pure-control-group\">"
|
|
||||||
"<label for=\"ip\">Netmask</label>"
|
|
||||||
"<input id=\"netmask\" name=\"netmas\" type=\"text\" value=\"{{WIFI_CFG_NM}}\">"
|
|
||||||
"</div>"
|
|
||||||
"<div class=\"pure-control-group\">"
|
|
||||||
"<label for=\"ip\">DNS</label>"
|
|
||||||
"<input id=\"netmask\" name=\"dns\" type=\"text\" value=\"{{WIFI_CFG_DNS}}\">"
|
|
||||||
"</div>"
|
|
||||||
"<div class=\"pure-controls\">"
|
|
||||||
"<button type=\"submit\" class=\"pure-button pure-button-primary\">Save</button>"
|
|
||||||
"</div>"
|
|
||||||
"</form>";
|
|
||||||
return config_html;
|
|
||||||
}
|
|
62
firmware/data/config_template.html
Normal file
62
firmware/data/config_template.html
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
<form class="pure-form pure-form-aligned" action="/" method="post">
|
||||||
|
<h3>Config</h3>
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label for="startup">
|
||||||
|
<strong>Startup</strong>
|
||||||
|
</label>
|
||||||
|
<select onchange="this.form.submit()" id="startup" name="startup">
|
||||||
|
<option {{STARTUP_SELECTED_LS_0}} value="0">Last state</option>
|
||||||
|
<option {{STARTUP_SELECTED_ON_1}} value="1">On</option>
|
||||||
|
<option {{STARTUP_SELECTED_OFF_2}} value="2">Off</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label for="scene">
|
||||||
|
<strong>Scene</strong>
|
||||||
|
</label>
|
||||||
|
<select onchange="this.form.submit()" id="scene" name="scene">
|
||||||
|
<option {{SCENE_SELECTED_RELAX_0}} value="0">Relax</option>
|
||||||
|
<option {{SCENE_SELECTED_BRIGHT_1}} value="1">Bright</option>
|
||||||
|
<option {{SCENE_SELECTED_NIGHT_2}} value="2">Night</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<h3>Wifi</h3>
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label for="ip">SSID</label>
|
||||||
|
<input id="ssid" name="ssid" type="text" value="{{WIFI_SSID}}">
|
||||||
|
</div>
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label for="wpw">Passphrase</label>
|
||||||
|
<input id="wpw" name="wpw" type="text" placeholder="1234password">
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<h3>Network</h3>
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label for="dip">
|
||||||
|
<strong>Dynamic-IP</strong>
|
||||||
|
</label>
|
||||||
|
<a class="pure-button {{DIP_LINK_ON_PRIMARY}}" href="/?dip=true">ON</a>
|
||||||
|
<a class="pure-button {{DIP_LINK_OFF_PRIMARY}}" href="/?dip=false">OFF</a>
|
||||||
|
</div>
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label for="ip">IP</label>
|
||||||
|
<input id="ip" name="ip" type="text" value="{{WIFI_CFG_IP}}">
|
||||||
|
</div>
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label for="gwip">Gateway IP</label>
|
||||||
|
<input id="gwip" name="gwip" type="text" value="{{WIFI_CFG_GW}}">
|
||||||
|
</div>
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label for="ip">Netmask</label>
|
||||||
|
<input id="netmask" name="netmas" type="text" value="{{WIFI_CFG_NM}}">
|
||||||
|
</div>
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label for="ip">DNS</label>
|
||||||
|
<input id="netmask" name="dns" type="text" value="{{WIFI_CFG_DNS}}">
|
||||||
|
</div>
|
||||||
|
<div class="pure-controls">
|
||||||
|
<button type="submit" class="pure-button pure-button-primary">Save</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
175
firmware/data/index_template_bottom.html
Normal file
175
firmware/data/index_template_bottom.html
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
<!-- bottom -->
|
||||||
|
<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_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);
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</body>
|
||||||
|
</html>
|
7
firmware/data/index_template_middle.html
Normal file
7
firmware/data/index_template_middle.html
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<!-- middle -->
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div id="plot_chart"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
91
firmware/data/index_template_top.html
Normal file
91
firmware/data/index_template_top.html
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style></style>
|
||||||
|
<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">
|
||||||
|
</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>
|
29
firmware/data/light_control_template.html
Normal file
29
firmware/data/light_control_template.html
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<h4>Light {{LIGHT_NUMBER}}</h4>
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label for="power">
|
||||||
|
<strong>Power</strong>
|
||||||
|
</label>
|
||||||
|
<a id="on{{LIGHT_NUMBER_DEC}}_on" class="pure-button" href="#">ON</a>
|
||||||
|
<a id="on{{LIGHT_NUMBER_DEC}}_off" class="pure-button" href="#">OFF</a>
|
||||||
|
</div>
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label for="bri{{LIGHT_NUMBER_DEC}}">Bri</label>
|
||||||
|
<input id="bri{{LIGHT_NUMBER_DEC}}" onchange="sendSliderValue({{LIGHT_NUMBER}})" name="bri{{LIGHT_NUMBER_DEC}}" type="range" min="0" max="255" value="25">
|
||||||
|
|
||||||
|
<span id="bri{{LIGHT_NUMBER_DEC}}_val" name="bri{{LIGHT_NUMBER_DEC}}">9</span>
|
||||||
|
%
|
||||||
|
<br>
|
||||||
|
<label for="light{{LIGHT_NUMBER_DEC}}_pwm">PWM-Value</label>
|
||||||
|
<input type="range" min="0" max="100" value="0" id="light{{LIGHT_NUMBER_DEC}}_pwm" disabled>
|
||||||
|
|
||||||
|
<span id="light{{LIGHT_NUMBER_DEC}}_pwm_txt"></span>
|
||||||
|
%
|
||||||
|
<script>
|
||||||
|
var slider{{LIGHT_NUMBER_DEC}} = document.getElementById("bri{{LIGHT_NUMBER_DEC}}");
|
||||||
|
var output{{LIGHT_NUMBER_DEC}} = document.getElementById("bri{{LIGHT_NUMBER_DEC}}_val");
|
||||||
|
output{{LIGHT_NUMBER_DEC}}.innerHTML = (Math.round((slider{{LIGHT_NUMBER_DEC}}.value * 100.0 / 255.0) * 100) / 100).toFixed(2);
|
||||||
|
slider{{LIGHT_NUMBER_DEC}}.oninput = function() {
|
||||||
|
output{{LIGHT_NUMBER_DEC}}.innerHTML = (Math.round((this.value * 100.0 / 255.0) * 100) / 100).toFixed(2);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</div>
|
|
@ -1,3 +1,4 @@
|
||||||
|
<div id="tab-config">
|
||||||
<form class="pure-form pure-form-aligned" action="/" method="post">
|
<form class="pure-form pure-form-aligned" action="/" method="post">
|
||||||
<h3>Config</h3>
|
<h3>Config</h3>
|
||||||
<div class="pure-control-group">
|
<div class="pure-control-group">
|
||||||
|
@ -59,4 +60,4 @@
|
||||||
<button type="submit" class="pure-button pure-button-primary">Save</button>
|
<button type="submit" class="pure-button pure-button-primary">Save</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</div><!-- end of config div -->
|
|
@ -1,102 +1,18 @@
|
||||||
<!doctype html>
|
<!-- bottom -->
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<style></style>
|
|
||||||
<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">
|
|
||||||
</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>
|
<script>
|
||||||
var links = document.querySelectorAll('[id^="tc_on"]');
|
var tabMain = document.getElementById("tab-main");
|
||||||
links.forEach(function(link) {
|
var tabConfig = document.getElementById("tab-config");
|
||||||
link.addEventListener('click', function(event) {
|
|
||||||
event.preventDefault();
|
document.getElementById("tab1-a").addEventListener("click", function() {
|
||||||
var xhr = new XMLHttpRequest();
|
tabMain.classList.add("visible");
|
||||||
xhr.open('GET', 'http://{{IP_ADDRESS}}/?tc=true', true);
|
tabConfig.classList.remove("visible");
|
||||||
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');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById("tab2-a").addEventListener("click", function() {
|
||||||
|
tabMain.classList.remove("visible");
|
||||||
|
tabConfig.classList.add("visible");
|
||||||
});
|
});
|
||||||
</script>
|
</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>
|
<script>
|
||||||
function loadGraphData() {
|
function loadGraphData() {
|
||||||
console.log('----> generate graph <----');
|
console.log('----> generate graph <----');
|
7
firmware/data/org/index_template_middle.html
Normal file
7
firmware/data/org/index_template_middle.html
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<!-- middle -->
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div id="plot_chart"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
111
firmware/data/org/index_template_top.html
Normal file
111
firmware/data/org/index_template_top.html
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style></style>
|
||||||
|
<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-main, #tab-config {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#tab-main.visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
#tab-config.visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</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>
|
||||||
|
<a href="#" id="tab1-a" class="pure-button">Main</a>
|
||||||
|
<a href="#" id="tab2-a" class="pure-button">Config</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="tab-main">
|
||||||
|
<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>
|
||||||
|
</div><!-- end of main-tab div -->
|
||||||
|
<br>
|
||||||
|
<table border=0>
|
||||||
|
<tr>
|
||||||
|
<td>
|
|
@ -1,3 +1,4 @@
|
||||||
|
//********************************//
|
||||||
|
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
#include <ESP8266mDNS.h>
|
#include <ESP8266mDNS.h>
|
||||||
|
@ -6,13 +7,10 @@
|
||||||
#include <WiFiManager.h>
|
#include <WiFiManager.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <EEPROM.h>
|
#include <EEPROM.h>
|
||||||
|
#include <FS.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "index_html.h"
|
|
||||||
#include "light_control_html.h"
|
|
||||||
#include "config_html.h"
|
|
||||||
|
|
||||||
//********* Config block *********//
|
//********* Config block *********//
|
||||||
// blue, warmwhite, purple, white&red&green
|
// blue, warmwhite, purple, white&red&green
|
||||||
// blau, schwarz, rot, weiß
|
// blau, schwarz, rot, weiß
|
||||||
|
@ -190,6 +188,59 @@ uint16_t calcPWM(float tbri)
|
||||||
|
|
||||||
void read_eeprom_config()
|
void read_eeprom_config()
|
||||||
{
|
{
|
||||||
|
uint8_t tmp = EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS);
|
||||||
|
if (tmp == TIMING_CONTROL_DISABLED)
|
||||||
|
{
|
||||||
|
tc_enabled = TIMING_CONTROL_DISABLED;
|
||||||
|
|
||||||
|
} else if (tmp == TIMING_CONTROL_ENABLED)
|
||||||
|
{
|
||||||
|
tc_enabled = TIMING_CONTROL_ENABLED;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Write default value
|
||||||
|
EEPROM.write(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS, TIMING_CONTROL_DISABLED);
|
||||||
|
EEPROM.commit();
|
||||||
|
tc_enabled = TIMING_CONTROL_DISABLED;
|
||||||
|
Serial.println("Written default timing control config to EEPROM (disabled)");
|
||||||
|
}
|
||||||
|
Serial.println("Timing Control status: " + (String)tc_enabled);
|
||||||
|
|
||||||
|
if (EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) > 2)
|
||||||
|
{
|
||||||
|
// set the default value on uninitialized EEPROM
|
||||||
|
EEPROM.write(EEPROM_LAST_STATE_STARTUP_ADDRESS, 0);
|
||||||
|
EEPROM.commit();
|
||||||
|
Serial.println("Written default 'last state' config to EEPROM");
|
||||||
|
}
|
||||||
|
Serial.println("Last state startup setting: " + (String)EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS));
|
||||||
|
|
||||||
|
if (EEPROM.read(EEPROM_SCENE_ADDRESS) > 2)
|
||||||
|
{
|
||||||
|
// set the default value on uninitialized EEPROM
|
||||||
|
EEPROM.write(EEPROM_SCENE_ADDRESS, 0);
|
||||||
|
EEPROM.commit();
|
||||||
|
Serial.println("Written default scene config to EEPROM");
|
||||||
|
}
|
||||||
|
Serial.println("Scene setting: " + (String)EEPROM.read(EEPROM_SCENE_ADDRESS));
|
||||||
|
|
||||||
|
#ifdef USE_STATIC_IP
|
||||||
|
if (EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS) > 1)
|
||||||
|
{
|
||||||
|
EEPROM.write(EEPROM_DYNAMIC_IP_ADDRESS, 0);
|
||||||
|
EEPROM.commit();
|
||||||
|
Serial.println("Written default dynamic IP setting (disabled) to EEPROM");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS) > 1)
|
||||||
|
{
|
||||||
|
EEPROM.write(EEPROM_DYNAMIC_IP_ADDRESS, 1);
|
||||||
|
EEPROM.commit();
|
||||||
|
Serial.println("Written default dynamic IP setting (enabled) to EEPROM");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Serial.println("Dynamic IP setting: " + (String)EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS));
|
||||||
|
|
||||||
for (uint8_t light = 0; light < LIGHTS_COUNT; light++)
|
for (uint8_t light = 0; light < LIGHTS_COUNT; light++)
|
||||||
{
|
{
|
||||||
apply_scene(EEPROM.read(EEPROM_SCENE_ADDRESS), light);
|
apply_scene(EEPROM.read(EEPROM_SCENE_ADDRESS), light);
|
||||||
|
@ -204,45 +255,6 @@ void read_eeprom_config()
|
||||||
Serial.println("light[" + (String)light + "] = " + (String)light_state[light]);
|
Serial.println("light[" + (String)light + "] = " + (String)light_state[light]);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t tmp = EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS);
|
|
||||||
if (tmp == TIMING_CONTROL_DISABLED)
|
|
||||||
{
|
|
||||||
tc_enabled = TIMING_CONTROL_DISABLED;
|
|
||||||
|
|
||||||
} else if (tmp == TIMING_CONTROL_ENABLED)
|
|
||||||
{
|
|
||||||
tc_enabled = TIMING_CONTROL_ENABLED;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
EEPROM.write(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS, TIMING_CONTROL_DISABLED);
|
|
||||||
EEPROM.commit();
|
|
||||||
tc_enabled = TIMING_CONTROL_DISABLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
Serial.println("tc_enabled = " + (String)tc_enabled);
|
|
||||||
|
|
||||||
if (EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) == 255)
|
|
||||||
{
|
|
||||||
// set the default value on uninitialized EEPROM
|
|
||||||
EEPROM.write(EEPROM_LAST_STATE_STARTUP_ADDRESS, 0);
|
|
||||||
EEPROM.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_STATIC_IP
|
|
||||||
if (EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS) == 255)
|
|
||||||
{
|
|
||||||
EEPROM.write(EEPROM_DYNAMIC_IP_ADDRESS, 0);
|
|
||||||
EEPROM.commit();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS) == 255)
|
|
||||||
{
|
|
||||||
EEPROM.write(EEPROM_DYNAMIC_IP_ADDRESS, 1);
|
|
||||||
EEPROM.commit();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//********************************//
|
//********************************//
|
||||||
|
@ -251,8 +263,22 @@ void setup()
|
||||||
{
|
{
|
||||||
EEPROM.begin(256);
|
EEPROM.begin(256);
|
||||||
|
|
||||||
|
SPIFFS.begin();
|
||||||
|
|
||||||
Serial.begin(SERIAL_BAUD_RATE);
|
Serial.begin(SERIAL_BAUD_RATE);
|
||||||
|
|
||||||
|
Serial.flush();
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
Dir dir = SPIFFS.openDir("/");
|
||||||
|
Serial.println("\n\nSPIFFS directory content:");
|
||||||
|
while (dir.next())
|
||||||
|
{
|
||||||
|
String fileName = dir.fileName();
|
||||||
|
size_t fileSize = dir.fileSize();
|
||||||
|
Serial.printf("Datei Name: %s, Größe: %s\n", fileName.c_str(), formatBytes(fileSize).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
if (EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS) == 0)
|
if (EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS) == 0)
|
||||||
{
|
{
|
||||||
WiFi.config(strip_ip, gateway_ip, subnet_mask, dns);
|
WiFi.config(strip_ip, gateway_ip, subnet_mask, dns);
|
||||||
|
@ -293,8 +319,10 @@ void setup()
|
||||||
|
|
||||||
init_webserver();
|
init_webserver();
|
||||||
|
|
||||||
|
Serial.println("Init timinc control");
|
||||||
tc_init();
|
tc_init();
|
||||||
|
|
||||||
|
Serial.println("Starting webserver");
|
||||||
server.begin();
|
server.begin();
|
||||||
} // end of setup
|
} // end of setup
|
||||||
|
|
||||||
|
@ -562,6 +590,7 @@ void init_webserver()
|
||||||
if (tmp == 0 && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == 0)
|
if (tmp == 0 && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == 0)
|
||||||
{
|
{
|
||||||
EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_ON);
|
EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_ON);
|
||||||
|
EEPROM.commit();
|
||||||
}
|
}
|
||||||
Serial.print("Light ");
|
Serial.print("Light ");
|
||||||
Serial.print(light);
|
Serial.print(light);
|
||||||
|
@ -574,6 +603,7 @@ void init_webserver()
|
||||||
if (tmp == 0 && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == 1)
|
if (tmp == 0 && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == 1)
|
||||||
{
|
{
|
||||||
EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_OFF);
|
EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_OFF);
|
||||||
|
EEPROM.commit();
|
||||||
}
|
}
|
||||||
Serial.print("Light ");
|
Serial.print("Light ");
|
||||||
Serial.print(light);
|
Serial.print(light);
|
||||||
|
@ -581,8 +611,6 @@ void init_webserver()
|
||||||
Serial.println(light_state[light]);
|
Serial.println(light_state[light]);
|
||||||
}
|
}
|
||||||
|
|
||||||
EEPROM.commit();
|
|
||||||
|
|
||||||
if (tc_enabled == TIMING_CONTROL_DISABLED)
|
if (tc_enabled == TIMING_CONTROL_DISABLED)
|
||||||
{
|
{
|
||||||
process_lightdata(light, default_transitiontime);
|
process_lightdata(light, default_transitiontime);
|
||||||
|
@ -608,7 +636,8 @@ void init_webserver()
|
||||||
|
|
||||||
} // process all lights
|
} // process all lights
|
||||||
|
|
||||||
if (server.hasArg("resettc")) { // reqrite the tc config and reboot
|
if (server.hasArg("resettc"))
|
||||||
|
{ // reqrite the tc config and reboot
|
||||||
tc_write_default();
|
tc_write_default();
|
||||||
ESP.reset();
|
ESP.reset();
|
||||||
}
|
}
|
||||||
|
@ -620,13 +649,18 @@ void init_webserver()
|
||||||
|
|
||||||
// ***** Generate HTML page ***** //
|
// ***** Generate HTML page ***** //
|
||||||
|
|
||||||
server.sendHeader("Content-Type", "text/html");
|
String tmp1 = genHMTLTop();
|
||||||
server.sendHeader("Connection", "close");
|
|
||||||
server.sendHeader("Access-Control-Allow-Origin", "*");
|
String tmp2 = genLightControlHTML();
|
||||||
server.send(200);
|
|
||||||
server.sendContent(replacePlaceholder(replaceLightsControl(getIndexHTMLTop())));
|
String tmp3 = getIndexHTMLMiddle();
|
||||||
server.sendContent(replacePlaceholder(getConfigHTML()));
|
|
||||||
server.sendContent(replacePlaceholder(getIndexHTMLBottom()));
|
String tmp4 = genConfigHTML();
|
||||||
|
|
||||||
|
String tmp5 = genHMTLBottom();
|
||||||
|
|
||||||
|
server.send(200, "text/html", tmp1 + tmp2 + tmp3 + tmp4 + tmp5);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("/reset", []()
|
server.on("/reset", []()
|
||||||
|
@ -639,9 +673,48 @@ void init_webserver()
|
||||||
server.onNotFound(handleNotFound);
|
server.onNotFound(handleNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
String replacePlaceholder(String in)
|
//********************************//
|
||||||
|
|
||||||
|
String genHMTLTop()
|
||||||
|
{
|
||||||
|
return replacePlaceholder(getIndexHTMLTop());
|
||||||
|
}
|
||||||
|
|
||||||
|
String genHMTLBottom()
|
||||||
|
{
|
||||||
|
return replacePlaceholder(getIndexHTMLBottom());
|
||||||
|
}
|
||||||
|
|
||||||
|
String genConfigHTML()
|
||||||
|
{
|
||||||
|
// +++++ Generate config part of the page +++++
|
||||||
|
return replacePlaceholder(getConfigHTML());
|
||||||
|
}
|
||||||
|
|
||||||
|
String genLightControlHTML()
|
||||||
|
{
|
||||||
|
String http_content = "";
|
||||||
|
// +++++ Generate lights part of the HTML page +++++
|
||||||
|
// Light control
|
||||||
|
for (uint8 light_num = 0; light_num < LIGHTS_COUNT; light_num++)
|
||||||
|
{
|
||||||
|
// Generate lights part of the HTML page
|
||||||
|
String tmp_light_content = getLightControlHTML();
|
||||||
|
|
||||||
|
// on/off buttons and slider
|
||||||
|
tmp_light_content.replace("{{LIGHT_NUMBER}}", (String)(light_num + 1));
|
||||||
|
tmp_light_content.replace("{{LIGHT_NUMBER_DEC}}", (String)light_num);
|
||||||
|
|
||||||
|
// add the lights code to the html output string
|
||||||
|
http_content += tmp_light_content;
|
||||||
|
}
|
||||||
|
return http_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
//********************************//
|
||||||
|
|
||||||
|
String replacePlaceholder(String http_content)
|
||||||
{
|
{
|
||||||
String http_content = in;
|
|
||||||
|
|
||||||
http_content.replace("{{LIGHT_NAME}}", (String)light_name);
|
http_content.replace("{{LIGHT_NAME}}", (String)light_name);
|
||||||
|
|
||||||
|
@ -706,31 +779,27 @@ String replacePlaceholder(String in)
|
||||||
http_content.replace("{{SCENE_SELECTED_NIGHT_2}}", "");
|
http_content.replace("{{SCENE_SELECTED_NIGHT_2}}", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate lights part of the HTML page
|
|
||||||
String config_content = getConfigHTML();
|
|
||||||
|
|
||||||
// Wifi settings
|
// Wifi settings
|
||||||
config_content.replace("{{WIFI_SSID}}", WiFi.SSID());
|
http_content.replace("{{WIFI_SSID}}", WiFi.SSID());
|
||||||
|
|
||||||
// Network settings
|
// Network settings
|
||||||
uint8_t dip = EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS);
|
uint8_t dip = EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS);
|
||||||
if (dip)
|
if (dip)
|
||||||
{
|
{
|
||||||
config_content.replace("{{DIP_LINK_ON_PRIMARY}}", "pure-button-primary");
|
http_content.replace("{{DIP_LINK_ON_PRIMARY}}", "pure-button-primary");
|
||||||
config_content.replace("{{DIP_LINK_OFF_PRIMARY}}", "");
|
http_content.replace("{{DIP_LINK_OFF_PRIMARY}}", "");
|
||||||
} else {
|
} else {
|
||||||
config_content.replace("{{DIP_LINK_OFF_PRIMARY}}", "pure-button-primary");
|
http_content.replace("{{DIP_LINK_OFF_PRIMARY}}", "pure-button-primary");
|
||||||
config_content.replace("{{DIP_LINK_ON_PRIMARY}}", "");
|
http_content.replace("{{DIP_LINK_ON_PRIMARY}}", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ip config
|
// network config
|
||||||
config_content.replace("{{WIFI_CFG_IP}}", WiFi.localIP().toString());
|
http_content.replace("{{WIFI_CFG_IP}}", WiFi.localIP().toString());
|
||||||
config_content.replace("{{WIFI_CFG_GW}}", WiFi.gatewayIP().toString());
|
http_content.replace("{{WIFI_CFG_GW}}", WiFi.gatewayIP().toString());
|
||||||
config_content.replace("{{WIFI_CFG_NM}}", WiFi.subnetMask().toString());
|
http_content.replace("{{WIFI_CFG_NM}}", WiFi.subnetMask().toString());
|
||||||
config_content.replace("{{WIFI_CFG_DNS}}", WiFi.dnsIP().toString());
|
http_content.replace("{{WIFI_CFG_DNS}}", WiFi.dnsIP().toString());
|
||||||
|
|
||||||
http_content.replace("{{CONFIG_PAGE}}", config_content);
|
|
||||||
|
|
||||||
|
// add the current ip address to the page
|
||||||
http_content.replace("{{IP_ADDRESS}}", WiFi.localIP().toString());
|
http_content.replace("{{IP_ADDRESS}}", WiFi.localIP().toString());
|
||||||
|
|
||||||
// set the pwm values
|
// set the pwm values
|
||||||
|
@ -740,25 +809,73 @@ String replacePlaceholder(String in)
|
||||||
return http_content;
|
return http_content;
|
||||||
}
|
}
|
||||||
|
|
||||||
String replaceLightsControl(String in)
|
//********************************//
|
||||||
{
|
|
||||||
String light_content = "";
|
|
||||||
// Light control
|
|
||||||
for (uint8 light_num = 0; light_num < LIGHTS_COUNT; light_num++)
|
|
||||||
{
|
|
||||||
// Generate lights part of the HTML page
|
|
||||||
String tmp_light_content = getLightControlHTML();
|
|
||||||
|
|
||||||
// on/off buttons and slider
|
String loadSPIFFSFile(String fname)
|
||||||
tmp_light_content.replace("{{LIGHT_NUMBER}}", (String)(light_num + 1));
|
{
|
||||||
tmp_light_content.replace("{{LIGHT_NUMBER_DEC}}", (String)light_num);
|
File file = SPIFFS.open(fname, "r");
|
||||||
|
if (!file)
|
||||||
// add the lights code to the html output string
|
{
|
||||||
light_content += tmp_light_content;
|
Serial.println("Failed to open file " + fname);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String contents = file.readString();
|
||||||
|
file.close();
|
||||||
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the created lights control code to the html output
|
//********************************//
|
||||||
in.replace("{{LIGHTS_CONTROL}}", light_content);
|
|
||||||
|
|
||||||
return in;
|
String getIndexHTMLTop()
|
||||||
|
{
|
||||||
|
// load file
|
||||||
|
return loadSPIFFSFile("/index_template_top.html");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getIndexHTMLMiddle()
|
||||||
|
{
|
||||||
|
// load file
|
||||||
|
return loadSPIFFSFile("/index_template_middle.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
String getIndexHTMLBottom()
|
||||||
|
{
|
||||||
|
// load file
|
||||||
|
return loadSPIFFSFile("/index_template_bottom.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
//********************************//
|
||||||
|
|
||||||
|
String getConfigHTML()
|
||||||
|
{
|
||||||
|
// load file
|
||||||
|
return loadSPIFFSFile("/config_template.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
//********************************//
|
||||||
|
|
||||||
|
String getLightControlHTML()
|
||||||
|
{
|
||||||
|
// load file
|
||||||
|
return loadSPIFFSFile("/light_control_template.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
//********************************//
|
||||||
|
|
||||||
|
String formatBytes(size_t bytes)
|
||||||
|
{
|
||||||
|
if (bytes < 1024)
|
||||||
|
{
|
||||||
|
return String(bytes) + " B";
|
||||||
|
} else if (bytes < (1024 * 1024))
|
||||||
|
{
|
||||||
|
return String(bytes / 1024.0) + " KB";
|
||||||
|
} else if (bytes < (1024 * 1024 * 1024))
|
||||||
|
{
|
||||||
|
return String(bytes / 1024.0 / 1024.0) + " MB";
|
||||||
|
} else {
|
||||||
|
return String(bytes / 1024.0 / 1024.0 / 1024.0) + " GB";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//********************************//
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 112 KiB |
Binary file not shown.
Before Width: | Height: | Size: 94 KiB |
|
@ -1,283 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
String getIndexHTMLTop()
|
|
||||||
{
|
|
||||||
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 - {{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\">"
|
|
||||||
"</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>";
|
|
||||||
return index_html;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getIndexHTMLBottom()
|
|
||||||
{
|
|
||||||
const char index_html[] = "<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_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);"
|
|
||||||
"</script>"
|
|
||||||
"</div>"
|
|
||||||
"</fieldset>"
|
|
||||||
"</body>"
|
|
||||||
"</html>";
|
|
||||||
return String(index_html);
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
|
|
||||||
String getLightControlHTML()
|
|
||||||
{
|
|
||||||
String light_control_html = "<h4>Light {{LIGHT_NUMBER}}</h4>"
|
|
||||||
"<div class=\"pure-control-group\">"
|
|
||||||
"<label for=\"power\">"
|
|
||||||
"<strong>Power</strong>"
|
|
||||||
"</label>"
|
|
||||||
"<a id=\"on{{LIGHT_NUMBER_DEC}}_on\" class=\"pure-button\" href=\"#\">ON</a>"
|
|
||||||
"<a id=\"on{{LIGHT_NUMBER_DEC}}_off\" class=\"pure-button\" href=\"#\">OFF</a>"
|
|
||||||
"</div>"
|
|
||||||
"<div class=\"pure-control-group\">"
|
|
||||||
"<label for=\"bri{{LIGHT_NUMBER_DEC}}\">Bri</label>"
|
|
||||||
"<input id=\"bri{{LIGHT_NUMBER_DEC}}\" onchange=\"sendSliderValue({{LIGHT_NUMBER}})\" name=\"bri{{LIGHT_NUMBER_DEC}}\" type=\"range\" min=\"0\" max=\"255\" value=\"25\">"
|
|
||||||
" "
|
|
||||||
"<span id=\"bri{{LIGHT_NUMBER_DEC}}_val\" name=\"bri{{LIGHT_NUMBER_DEC}}\">9</span>"
|
|
||||||
"%"
|
|
||||||
"<br>"
|
|
||||||
"<label for=\"light{{LIGHT_NUMBER_DEC}}_pwm\">PWM-Value</label>"
|
|
||||||
"<input type=\"range\" min=\"0\" max=\"100\" value=\"0\" id=\"light{{LIGHT_NUMBER_DEC}}_pwm\" disabled>"
|
|
||||||
" "
|
|
||||||
"<span id=\"light{{LIGHT_NUMBER_DEC}}_pwm_txt\"></span>"
|
|
||||||
"%"
|
|
||||||
"<script>"
|
|
||||||
"var slider{{LIGHT_NUMBER_DEC}} = document.getElementById(\"bri{{LIGHT_NUMBER_DEC}}\");"
|
|
||||||
"var output{{LIGHT_NUMBER_DEC}} = document.getElementById(\"bri{{LIGHT_NUMBER_DEC}}_val\");"
|
|
||||||
"output{{LIGHT_NUMBER_DEC}}.innerHTML = (Math.round((slider{{LIGHT_NUMBER_DEC}}.value * 100.0 / 255.0) * 100) / 100).toFixed(2);"
|
|
||||||
"slider{{LIGHT_NUMBER_DEC}}.oninput = function() {"
|
|
||||||
"output{{LIGHT_NUMBER_DEC}}.innerHTML = (Math.round((this.value * 100.0 / 255.0) * 100) / 100).toFixed(2);"
|
|
||||||
"}"
|
|
||||||
"</script>"
|
|
||||||
"</div>";
|
|
||||||
return light_control_html;
|
|
||||||
}
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
cat $1 | sed -e"s/^ *//ig" | sed -e 's/"/\\"/ig' | sed -e "s/^/\"/ig" | sed -e "s/$/\"/ig"
|
cat $1 | sed -e"s/^ *//ig"
|
||||||
echo ";"
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue