Compare commits

..

No commits in common. "fc9baddfbdcdecd0ebf228d9160925869c6601e8" and "076a0162c4fd79936a303545ec032a1e8401be72" have entirely different histories.

21 changed files with 788 additions and 409 deletions

Binary file not shown.

Binary file not shown.

View file

@ -6,8 +6,7 @@
#define LOCAL_TIMEZONE_STRING "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00" // Berlin, Germany - https://sites.google.com/a/usapiens.com/opnode/time-zones
//#define DEVELOPMENT
#define LIGHT_NAME_STR "Dimmable Hue Light" // default light name
#define light_name "Dimmable Hue Light" // default light name
#define LIGHTS_COUNT 4 // do not modify because luminie p30 only has 4 channel, never set above 80
@ -24,3 +23,4 @@
#define TIME_LIGHTENGINE_INTERVAL_MS (1000UL / BRI_MOD_STEPS_PER_SEC) // BRI_MOD_STEPS_PER_SEC steps per second to in-/decrease the brightness
#define MY_NTP_SERVER "de.pool.ntp.org"

View file

@ -1,9 +1,6 @@
<div id="tab-config" class="">
<form class="pure-form pure-form-aligned" action="/" method="post">
<br>
<label for="startup">
<strong>Light initialization</strong>
</label>
<h3>Config</h3>
<div class="pure-control-group">
<label for="startup">
<strong>Startup</strong>
@ -25,9 +22,7 @@
</select>
</div>
<br>
<label for="startup">
<strong>Wifi</strong>
</label>
<h3>Wifi</h3>
<div class="pure-control-group">
<label for="ip">SSID</label>
<input id="ssid" name="ssid" type="text" value="{{WIFI_SSID}}">
@ -37,9 +32,7 @@
<input id="wpw" name="wpw" type="text" placeholder="1234password">
</div>
<br>
<label for="startup">
<strong>Network</strong>
</label>
<h3>Network</h3>
<div class="pure-control-group">
<label for="dip">
<strong>Dynamic-IP</strong>

View file

@ -0,0 +1,63 @@
<div id="tab-config" class="">
<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>
</div><!-- end of config div -->

View file

@ -1,44 +1,25 @@
<!-- bottom -->
<script>
var tabMain = document.getElementById("tab-lights");
var tabMain = document.getElementById("tab-main");
var tabConfig = document.getElementById("tab-config");
var tabTDE = document.getElementById("tab-tde");
var amain = document.getElementById("tab1-a");
var acfg = document.getElementById("tab2-a");
var amain = document.getElementById("tab-a-lights");
var acfg = document.getElementById("tab-a-config");
var atde = document.getElementById("tab-a-tde");
document.getElementById("tab-a-lights").addEventListener("click", function() {
document.getElementById("tab1-a").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");
});
document.getElementById("tab-a-config").addEventListener("click", function() {
document.getElementById("tab2-a").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");
});
document.getElementById("tab-a-tde").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");
});
</script>
<script>
function loadGraphData() {
console.log('----> generate graph <----');
$.getJSON('/tc_data_blocks', function(data) {
@ -207,43 +188,41 @@ pwmElementTxt.innerText = pwmValue.toString();
}
updatePWMValues();
setInterval(updatePWMValues, 5000);
</script>
<script>
// 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');
});
});
</script>

View file

@ -0,0 +1,233 @@
<!-- bottom -->
<script>
var tabMain = document.getElementById("tab-main");
var tabConfig = document.getElementById("tab-config");
var amain = document.getElementById("tab1-a");
var acfg = document.getElementById("tab2-a");
document.getElementById("tab1-a").addEventListener("click", function() {
tabMain.classList.add("visible");
tabConfig.classList.remove("visible");
amain.classList.add("pure-button-primary");
acfg.classList.remove("pure-button-primary");
});
document.getElementById("tab2-a").addEventListener("click", function() {
tabMain.classList.remove("visible");
tabConfig.classList.add("visible");
acfg.classList.add("pure-button-primary");
amain.classList.remove("pure-button-primary");
});
</script>
<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>
<script>
// 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', true);
// Sende die Anfrage im Hintergrund
xhr.send();
updateLightState();
});
});
// 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', true);
// Sende die Anfrage im Hintergrund
xhr.send();
updateLightState();
});
});
</script>
</div>
</fieldset>
</body>
</html>

View file

@ -5,8 +5,4 @@
</td>
</tr>
</table>
</div><!-- end of lights control tab -->
<div id="tab-tde"> <!-- timing editor -->
Not implemented yet.
</div>
</div><!-- end of main-tab div -->

View file

@ -0,0 +1,8 @@
<!-- middle -->
</td>
<td>
<div id="plot_chart"></div>
</td>
</tr>
</table>
</div><!-- end of main-tab div -->

View file

@ -1,6 +1,7 @@
<!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>
@ -10,21 +11,15 @@
<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 {
#tab-main, #tab-config {
display: none;
background-color: #ffffff;
color: black;
font-weight: bold;
}
#tab-lights.visible {
#tab-main.visible {
display: block;
}
#tab-config.visible {
display: block;
}
#tab-tde.visible {
display: block;
}
</style>
</head>
<body>
@ -32,31 +27,32 @@ display: block;
<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>
<span class="pure-form-message">
<a href="/?alert=1">alert</a>
&nbsp;
<a href="/?reset=1">reset</a>
&nbsp;
<a href="/?resettc">reset timing control data</a>
&nbsp;
<a href="/update">update</a>
</span>
<label for="cb" class="pure-checkbox"></label>
</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>
<a href="#" id="tab1-a" class="pure-button pure-button-primary">Main</a>
<a href="#" id="tab2-a" class="pure-button">Config</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) {
@ -82,7 +78,15 @@ 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;
@ -102,6 +106,7 @@ console.error(`Error sending slider value to ${url}: ${error}`);
}
</script>
<br>
<div id="tab-main" class="visible">
<table border=0>
<tr>
<td>

View file

@ -0,0 +1,113 @@
<!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>
&nbsp;
<a href="/?reset=1">reset</a>
&nbsp;
<a href="/?resettc">reset timing control data</a>
&nbsp;
<a href="/update">update</a>
</span>
<label for="cb" class="pure-checkbox"></label>
</div>
<br>
<div>
<a href="#" id="tab1-a" class="pure-button pure-button-primary">Main</a>
<a href="#" id="tab2-a" class="pure-button">Config</a>
</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>
<div id="tab-main" class="visible">
<table border=0>
<tr>
<td>

View 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">
&nbsp;
<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>
&nbsp;
<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>

View file

@ -1,9 +1,6 @@
<div id="tab-config" class="">
<form class="pure-form pure-form-aligned" action="/" method="post">
<br>
<label for="startup">
<strong>Light initialization</strong>
</label>
<h3>Config</h3>
<div class="pure-control-group">
<label for="startup">
<strong>Startup</strong>
@ -25,9 +22,7 @@
</select>
</div>
<br>
<label for="startup">
<strong>Wifi</strong>
</label>
<h3>Wifi</h3>
<div class="pure-control-group">
<label for="ip">SSID</label>
<input id="ssid" name="ssid" type="text" value="{{WIFI_SSID}}">
@ -37,9 +32,7 @@
<input id="wpw" name="wpw" type="text" placeholder="1234password">
</div>
<br>
<label for="startup">
<strong>Network</strong>
</label>
<h3>Network</h3>
<div class="pure-control-group">
<label for="dip">
<strong>Dynamic-IP</strong>

View file

@ -0,0 +1,233 @@
<!-- bottom -->
<script>
var tabMain = document.getElementById("tab-main");
var tabConfig = document.getElementById("tab-config");
var amain = document.getElementById("tab1-a");
var acfg = document.getElementById("tab2-a");
document.getElementById("tab1-a").addEventListener("click", function() {
tabMain.classList.add("visible");
tabConfig.classList.remove("visible");
amain.classList.add("pure-button-primary");
acfg.classList.remove("pure-button-primary");
});
document.getElementById("tab2-a").addEventListener("click", function() {
tabMain.classList.remove("visible");
tabConfig.classList.add("visible");
acfg.classList.add("pure-button-primary");
amain.classList.remove("pure-button-primary");
});
</script>
<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>
<script>
// 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();
});
});
// 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();
});
});
</script>
</div>
</fieldset>
</body>
</html>

View file

@ -5,8 +5,4 @@
</td>
</tr>
</table>
</div><!-- end of lights control tab -->
<div id="tab-tde"> <!-- timing editor -->
Not implemented yet.
</div>
</div><!-- end of main-tab div -->

View file

@ -1,6 +1,7 @@
<!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>
@ -10,21 +11,15 @@
<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 {
#tab-main, #tab-config {
display: none;
background-color: #ffffff;
color: black;
font-weight: bold;
}
#tab-lights.visible {
#tab-main.visible {
display: block;
}
#tab-config.visible {
display: block;
}
#tab-tde.visible {
display: block;
}
</style>
</head>
<body>
@ -32,31 +27,32 @@
<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>
<span class="pure-form-message">
<a href="/?alert=1">alert</a>
&nbsp;
<a href="/?reset=1">reset</a>
&nbsp;
<a href="/?resettc">reset timing control data</a>
&nbsp;
<a href="/update">update</a>
</span>
<label for="cb" class="pure-checkbox"></label>
</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>
<a href="#" id="tab1-a" class="pure-button pure-button-primary">Main</a>
<a href="#" id="tab2-a" class="pure-button">Config</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) {
@ -82,7 +78,15 @@
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;
@ -102,6 +106,7 @@
}
</script>
<br>
<div id="tab-main" class="visible">
<table border=0>
<tr>
<td>

View file

@ -11,16 +11,7 @@
#include "config.h"
//********* preprocessor block *********//
#ifdef DEVELOPMENT
#define LIGHT_NAME "Dimmable Hue Light (DEV)"
#else
#define LIGHT_NAME LIGHT_NAME_STR
#endif
//********* Config block *********//
// blue, warmwhite, purple, white&red&green
// blau, schwarz, rot, weiß
// ch1, ch2, ch3, ch4
@ -279,8 +270,6 @@ void setup()
Serial.flush();
delay(1000);
//Serial.println("Flash size: " + (String)ESP.getFlashChipSize());
Dir dir = SPIFFS.openDir("/");
Serial.println("\n\nSPIFFS directory content:");
while (dir.next())
@ -305,7 +294,7 @@ void setup()
WiFi.mode(WIFI_STA);
WiFiManager wifiManager;
wifiManager.setConfigPortalTimeout(120);
wifiManager.autoConnect(LIGHT_NAME);
wifiManager.autoConnect(light_name);
IPAddress myIP = WiFi.localIP();
Serial.print("IP: ");
@ -460,7 +449,7 @@ void init_webserver()
char macString[32] = { 0 };
sprintf(macString, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
DynamicJsonDocument root(1024);
root["name"] = LIGHT_NAME;
root["name"] = light_name;
root["lights"] = LIGHTS_COUNT;
root["protocol"] = "native_multi";
root["modelid"] = "LWB010";
@ -728,7 +717,7 @@ String genLightControlHTML()
String replacePlaceholder(String http_content)
{
http_content.replace("{{LIGHT_NAME}}", (String)LIGHT_NAME);
http_content.replace("{{LIGHT_NAME}}", (String)light_name);
http_content.replace("{{LIGHT_COUNT}}", (String)LIGHTS_COUNT);
@ -736,14 +725,12 @@ String replacePlaceholder(String http_content)
if (tc_val == TIMING_CONTROL_ENABLED)
{
http_content.replace("{{TC_LINK_PRIMARY_ON}}", "pure-button-primary");
} else {
http_content.replace("{{TC_LINK_PRIMARY_ON}}", "");
}
if (tc_val == TIMING_CONTROL_DISABLED)
{
http_content.replace("{{TC_LINK_PRIMARY_OFF}}", "pure-button-primary");
} else {
http_content.replace("{{TC_LINK_PRIMARY_OFF}}", "");
}

View file

@ -1,254 +0,0 @@
<!-- bottom -->
<script>
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");
document.getElementById("tab-a-lights").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");
});
document.getElementById("tab-a-config").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");
});
document.getElementById("tab-a-tde").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");
});
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);
// 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');
});
});
</script>
</div>
</fieldset>
</body>
</html>

View file

@ -1,4 +1,4 @@
#!/bin/bash
cat $1 | sed -e"s/^ *//ig" | sed -e "s/^\/\/.*//ig"
cat $1 | sed -e"s/^ *//ig"

View file

@ -1,7 +1,7 @@
#!/bin/bash
bash ../../tools/html2string.sh ../html/index_template_top.html > index_template_top.html
bash ../../tools/html2string.sh ../html/index_template_middle.html > index_template_middle.html
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 org/index_template_top.html > index_template_top.html
bash ../../tools/html2string.sh org/index_template_middle.html > index_template_middle.html
bash ../../tools/html2string.sh org/index_template_bottom.html > index_template_bottom.html
bash ../../tools/html2string.sh org/config_template.html > config_template.html
bash ../../tools/html2string.sh org/light_control_template.html > light_control_template.html