Compare commits

...

12 commits

Author SHA1 Message Date
Kai Lauterbach 74a7a1e3a3 Added version info to the web interface, and the DEV string will only appear on development versions now. 2023-05-19 10:51:26 +02:00
Kai Lauterbach 6763bda9fb Updated binary files 2023-05-19 10:26:12 +02:00
Kai Lauterbach 5d1ea14e2e Added the functionality to rewrite the ip config by the web interface. 2023-05-19 10:21:36 +02:00
Kai Lauterbach c79e15d7a1 Fixed updateLightStateAndPWMValues call 2023-05-17 19:44:55 +02:00
Kai Lauterbach 91d2d867b0 Revert "Button initialization refactorized."
This reverts commit dbaa21bd30.
2023-05-17 19:39:00 +02:00
Kai Lauterbach 88b738ac75 Revert "Refactorized the Plotly graph code"
This reverts commit bb0c390937.
2023-05-17 19:38:55 +02:00
Kai Lauterbach bb0c390937 Refactorized the Plotly graph code 2023-05-17 19:01:32 +02:00
Kai Lauterbach dbaa21bd30 Button initialization refactorized. 2023-05-17 18:54:00 +02:00
Kai Lauterbach 8deac5fc15 Merged two very similar functions into one. 2023-05-17 17:15:10 +02:00
Kai Lauterbach df215a2c16 Added vscode arduino config file 2023-05-17 17:13:12 +02:00
Kai Lauterbach 3185b5ba27 Merge branch 'main' into develop 2023-05-17 14:11:01 +02:00
Kai Lauterbach c136983953 Fixed html web form id's 2023-05-16 11:58:21 +02:00
16 changed files with 219 additions and 86 deletions

15
.vscode/arduino.json vendored Normal file
View file

@ -0,0 +1,15 @@
{
"configuration": "xtal=80,vt=flash,exception=disabled,stacksmash=disabled,ssl=all,mmu=3232,non32xfer=fast,eesz=4M2M,led=2,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none,baud=460800",
"board": "esp8266:esp8266:nodemcuv2",
"port": "/dev/tty.usbserial-110",
"programmer": "AVRISP mkII",
"sketch": "firmware/firmware.ino",
"includePath": [
"/Users/klaute/Documents/Arduino/libraries",
"/Applications/Arduino.app/Contents/Java/hardware/tools/avr/avr/include",
"/Applications/Arduino.app/Contents/Java/hardware/tools/avr/avr/lib",
"/Applications/Arduino.app//Contents/Java/hardware/arduino/avr/libraries"
"/Applications/Arduino.app/Contents/Java/hardware/tools/avr/include",
"/Applications/Arduino.app/Contents/Java/hardware/tools/avr/x86_64-apple-darwin16.1.0/avr/include"
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 MiB

After

Width:  |  Height:  |  Size: 2 MiB

View file

@ -1,4 +1,6 @@
#define VERSION_STR "2.0.0"
#define USE_STATIC_IP //! uncomment to enable Static IP Adress
#define SERIAL_BAUD_RATE 115200
@ -7,7 +9,8 @@
//#define DEVELOPMENT
#define LIGHT_NAME_STR "Lumini/Lominie Pixie30/P30 light control" // default light name
#define LIGHT_NAME "Lumini/Lominie Pixie30/P30 light control" // default light name
#define LIGHT_NAME_DEV_POSTFIX " (DEV)"
#define LIGHTS_COUNT 4 // do not modify because luminie p30 only has 4 channel, never set above 80
@ -17,6 +20,10 @@
#define EEPROM_DYNAMIC_IP_ADDRESS 3
#define EEPROM_LAST_STATE_ADDRESS 4 // the first "last state" information for the first light
#define EEPROM_TIMING_DATA_ADDRESS (EEPROM_LAST_STATE_ADDRESS + LIGHTS_COUNT) // Stored data date per light ELE_USED; HH; MM; CH1; CH2; CH3; CH4;
#define EEPROM_IP_ADDRESS (EEPROM_TIMING_DATA_ADDRESS + 60) // 10 blocks of 6 byte per timing control data block = 60 byte EEPROM space
#define EEPROM_GW_ADDRESS (EEPROM_IP_ADDRESS + 4) // step 4 byte further IP
#define EEPROM_NM_ADDRESS (EEPROM_GW_ADDRESS + 4) // step 4 byte further GW
#define EEPROM_DNS_ADDRESS (EEPROM_NM_ADDRESS + 4) // step 4 byte further NM
#define BRI_MOD_STEPS_PER_SEC 25

View file

@ -272,15 +272,23 @@ if (document.getElementById('tab-tde').classList.contains('visible')) {
loadTCGraphData();
}
}, 2000);
function updateLightState() {
console.log('----> setting bri and power switch <----');
function updateLightStateAndPWMValues() {
console.log('----> setting bri, power switch, and pwm data <----');
const promises = [];
for (let i = 1; i <= {{LIGHT_COUNT}}; i++) {
const lightURL = `http://{{IP_ADDRESS}}/state?light=${i}`;
fetch(lightURL).then(response => response.json()).then(data => {
promises.push(fetch(lightURL).then(response => response.json()));
}
Promise.all(promises)
.then(dataArray => {
for (let i = 1; i <= {{LIGHT_COUNT}}; i++) {
const data = dataArray[i - 1];
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`);
const pwmElement = document.getElementById(`light${i - 1}_pwm`);
const pwmElementTxt = document.getElementById(`light${i - 1}_pwm_txt`);
briSlider.value = data.bri;
briSliderVal.innerHTML = (Math.round((data.bri * 100.0 / 255.0) * 100) / 100).toFixed(2);
if (data.on == true) {
@ -290,30 +298,18 @@ onLinkOff.classList.remove('pure-button-primary');
onLinkOn.classList.remove('pure-button-primary');
onLinkOff.classList.add('pure-button-primary');
}
}).catch(error => console.error(error));
}
}
setInterval(updateLightState, 10000);
updateLightState();
function updatePWMValues() {
console.log('----> setting pwm data <----');
for (let i = 0; i < {{LIGHT_COUNT}}; i++) {
const lightID = i + 1;
const pwmElement = document.getElementById(`light${i}_pwm`);
const pwmElementTxt = document.getElementById(`light${i}_pwm_txt`);
if (pwmElement) {
const url = `http://{{IP_ADDRESS}}/state?light=${lightID}`;
fetch(url).then(response => response.json()).then(data => {
const pwmValue = ((Math.round((data.curpwm - ((data.curpwm >= {{PWM_MIN}}) ? {{PWM_MIN}} : 0)) / {{PWM_MAX}} * 10000) / 100).toFixed(2));
pwmElement.innerText = pwmValue.toString();
pwmElement.value = pwmValue;
pwmElementTxt.innerText = pwmValue.toString();
}).catch(error => console.error(error));
}
}
})
.catch(error => console.error(error));
}
updatePWMValues();
setInterval(updatePWMValues, 5000);
updateLightStateAndPWMValues();
setInterval(updateLightStateAndPWMValues, 5000);
var links = document.querySelectorAll('[id^="on"][id$="_off"]');
links.forEach(function(link) {
link.addEventListener('click', function(event) {
@ -354,7 +350,7 @@ console.log('Error while sending data to server.');
}
};
xhr.send();
updateLightState();
updateLightStateAndPWMValues();
this.classList.add('pure-button-primary');
document.getElementById('on'+id+'_on').classList.remove('pure-button-primary');
});
@ -399,7 +395,7 @@ console.log('Error while sending data to server.');
}
};
xhr.send();
updateLightState();
updateLightStateAndPWMValues();
this.classList.add('pure-button-primary');
document.getElementById('on'+id+'_off').classList.remove('pure-button-primary');
});

View file

@ -56,15 +56,15 @@
<input id="gwip" name="gwip" type="text" value="{{WIFI_CFG_GW}}">
</div>
<div class="pure-control-group">
<label for="ip">Netmask</label>
<label for="netmask">Netmask</label>
<input id="netmask" name="netmas" type="text" value="{{WIFI_CFG_NM}}">
</div>
<div class="pure-control-group">
<label for="ip">DNS</label>
<label for="dns">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>
<button type="dns" class="pure-button pure-button-primary">Save</button>
</div>
</form>
</div><!-- end of config div -->

View file

@ -18,7 +18,6 @@
</td>
</tr>
</table>
<br>
<a href="#" id="save-button" class="pure-button pure-button-primary" onclick="sendDataToServer();">save</a>
</div>
</div> <!-- end of tab-tde -->
@ -26,5 +25,6 @@
</script>
</div>
</fieldset>
<p>{{VERSION_STR}}</p>
</body>
</html>

View file

@ -14,7 +14,7 @@
</head>
<body>
<fieldset>
<h3>{{LIGHT_NAME}}</h3>
<h3>{{LIGHT_NAME}}{{LIGHT_NAME_DEV_POSTFIX}}</h3>
<div class="toast"></div>
<div class="pure-form pure-form-aligned">
<div class="pure-controls">

View file

@ -13,12 +13,6 @@
//********* 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
@ -39,7 +33,7 @@ IPAddress dns (192, 168, 0, 1);
//********************************//
#define LIGHT_VERSION 2.1
#define LIGHT_VERSION 2.1 // diyHue light version
#define LAST_STATE_STARTUP_LIGHT_LAST_STATE 0
#define LAST_STATE_STARTUP_LIGHT_ON_STATE 1
@ -103,13 +97,13 @@ void setup()
Serial.printf("Datei Name: %s, Größe: %s\n", fileName.c_str(), formatBytes(fileSize).c_str());
}
read_eeprom_config();
if (EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS) == 0)
{
{ // static ip is used
WiFi.config(strip_ip, gateway_ip, subnet_mask, dns);
}
read_eeprom_config();
for (int j = 0; j < 200; j++)
{
lightEngine();
@ -260,6 +254,49 @@ void read_eeprom_config()
Serial.println("light[" + (String)light + "] = " + (String)light_state[light]);
}
// read IP, NetMask, GateWay and DNS from EEPROM or store default value
// only IPv4 is supported
if (EEPROM.read(EEPROM_IP_ADDRESS) == 255)
{
for (uint8_t i = 0; i < 4; i++)
{
EEPROM.write(EEPROM_IP_ADDRESS + i, strip_ip[i]);
EEPROM.write(EEPROM_GW_ADDRESS + i, gateway_ip[i]);
EEPROM.write(EEPROM_NM_ADDRESS + i, subnet_mask[i]);
EEPROM.write(EEPROM_DNS_ADDRESS + i, dns[i]);
}
} else {
if (EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS) == 0)
{
for (uint8_t i = 0; i < 4; i++)
{
strip_ip[i] = EEPROM.read(EEPROM_IP_ADDRESS + i);
gateway_ip[i] = EEPROM.read(EEPROM_GW_ADDRESS + i);
subnet_mask[i] = EEPROM.read(EEPROM_NM_ADDRESS + i);
dns[i] = EEPROM.read(EEPROM_DNS_ADDRESS + i);
}
Serial.println("IP from EEPROM: " +
(String)strip_ip[0] + "." +
(String)strip_ip[1] + "." +
(String)strip_ip[2] + "." +
(String)strip_ip[3]);
Serial.println("GW from EEPROM: " +
(String)gateway_ip[0] + "." +
(String)gateway_ip[1] + "." +
(String)gateway_ip[2] + "." +
(String)gateway_ip[3]);
Serial.println("NetMask from EEPROM: " +
(String)subnet_mask[0] + "." +
(String)subnet_mask[1] + "." +
(String)subnet_mask[2] + "." +
(String)subnet_mask[3]);
Serial.println("DNS from EEPROM: " +
(String)dns[0] + "." +
(String)dns[1] + "." +
(String)dns[2] + "." +
(String)dns[3]);
}
}
}
//********************************//

View file

@ -317,50 +317,49 @@ setInterval(function() {
}
}, 2000);
function updateLightState() {
console.log('----> setting bri and power switch <----');
function updateLightStateAndPWMValues() {
console.log('----> setting bri, power switch, and pwm data <----');
const promises = [];
for (let i = 1; i <= {{LIGHT_COUNT}}; i++) {
const lightURL = `http://{{IP_ADDRESS}}/state?light=${i}`;
fetch(lightURL).then(response => response.json()).then(data => {
const briSlider = document.getElementById(`bri${i - 1}`);
const briSliderVal = document.getElementById(`bri${i - 1}_val`);
const onLinkOn = document.getElementById(`on${i - 1}_on`);
const onLinkOff = document.getElementById(`on${i - 1}_off`);
briSlider.value = data.bri;
briSliderVal.innerHTML = (Math.round((data.bri * 100.0 / 255.0) * 100) / 100).toFixed(2);
if (data.on == true) {
onLinkOn.classList.add('pure-button-primary');
onLinkOff.classList.remove('pure-button-primary');
} else {
onLinkOn.classList.remove('pure-button-primary');
onLinkOff.classList.add('pure-button-primary');
}
}).catch(error => console.error(error));
promises.push(fetch(lightURL).then(response => response.json()));
}
}
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));
}
}
Promise.all(promises)
.then(dataArray => {
for (let i = 1; i <= {{LIGHT_COUNT}}; i++) {
const data = dataArray[i - 1];
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`);
const pwmElement = document.getElementById(`light${i - 1}_pwm`);
const pwmElementTxt = document.getElementById(`light${i - 1}_pwm_txt`);
briSlider.value = data.bri;
briSliderVal.innerHTML = (Math.round((data.bri * 100.0 / 255.0) * 100) / 100).toFixed(2);
if (data.on == true) {
onLinkOn.classList.add('pure-button-primary');
onLinkOff.classList.remove('pure-button-primary');
} else {
onLinkOn.classList.remove('pure-button-primary');
onLinkOff.classList.add('pure-button-primary');
}
if (pwmElement) {
const pwmValue = ((Math.round((data.curpwm - ((data.curpwm >= {{PWM_MIN}}) ? {{PWM_MIN}} : 0)) / {{PWM_MAX}} * 10000) / 100).toFixed(2));
pwmElement.innerText = pwmValue.toString();
pwmElement.value = pwmValue;
pwmElementTxt.innerText = pwmValue.toString();
}
}
})
.catch(error => console.error(error));
}
updatePWMValues();
setInterval(updatePWMValues, 5000);
updateLightStateAndPWMValues();
setInterval(updateLightStateAndPWMValues, 5000);
// Suche nach allen Links auf der Seite mit IDs von on0_off bis on3_off
var links = document.querySelectorAll('[id^="on"][id$="_off"]');
@ -410,7 +409,7 @@ links.forEach(function(link) {
// Sende die Anfrage im Hintergrund
xhr.send();
updateLightState();
updateLightStateAndPWMValues();
this.classList.add('pure-button-primary');
document.getElementById('on'+id+'_on').classList.remove('pure-button-primary');
});
@ -463,7 +462,7 @@ links.forEach(function(link) {
// Sende die Anfrage im Hintergrund
xhr.send();
updateLightState();
updateLightStateAndPWMValues();
this.classList.add('pure-button-primary');
document.getElementById('on'+id+'_off').classList.remove('pure-button-primary');
});

View file

@ -56,15 +56,15 @@
<input id="gwip" name="gwip" type="text" value="{{WIFI_CFG_GW}}">
</div>
<div class="pure-control-group">
<label for="ip">Netmask</label>
<label for="netmask">Netmask</label>
<input id="netmask" name="netmas" type="text" value="{{WIFI_CFG_NM}}">
</div>
<div class="pure-control-group">
<label for="ip">DNS</label>
<label for="dns">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>
<button type="dns" class="pure-button pure-button-primary">Save</button>
</div>
</form>
</div><!-- end of config div -->

View file

@ -19,7 +19,6 @@
</tr>
</table>
<br>
<a href="#" id="save-button" class="pure-button pure-button-primary" onclick="sendDataToServer();">save</a>
</div>
</div> <!-- end of tab-tde -->
@ -29,5 +28,6 @@
</div>
</fieldset>
<p>{{VERSION_STR}}</p>
</body>
</html>

View file

@ -14,7 +14,7 @@
</head>
<body>
<fieldset>
<h3>{{LIGHT_NAME}}</h3>
<h3>{{LIGHT_NAME}}{{LIGHT_NAME_DEV_POSTFIX}}</h3>
<div class="toast"></div>
<div class="pure-form pure-form-aligned">
<div class="pure-controls">

View file

@ -23,9 +23,9 @@
bool tc_testOngoing = false;
uint32_t tc_last_check = 60000;
uint32_t tc_last_check = TIME_CHECK_INTERVAL_MS; // initially check if new data needs to be read
uint8_t current_target_data_block = 255;
uint8_t current_target_data_block = 255; // no data processed yet
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, MY_NTP_SERVER);

View file

@ -286,7 +286,8 @@ void init_webserver()
}
}
if (server.hasArg("dip")) {
if (server.hasArg("dip"))
{
uint8_t tmp = EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS);
uint8_t tmp2 = (server.arg("dip") == "true" ? 1 : 0);
if (tmp != tmp2)
@ -298,6 +299,78 @@ void init_webserver()
}
}
if (server.hasArg("ip"))
{
strip_ip.fromString(server.arg("ip"));
// make it persistent to eeprom
EEPROM.write(EEPROM_IP_ADDRESS, strip_ip[0]);
EEPROM.write(EEPROM_IP_ADDRESS+1, strip_ip[1]);
EEPROM.write(EEPROM_IP_ADDRESS+2, strip_ip[2]);
EEPROM.write(EEPROM_IP_ADDRESS+3, strip_ip[3]);
EEPROM.commit();
Serial.println("IP set to: " +
(String)EEPROM.read(EEPROM_IP_ADDRESS) + "." +
(String)EEPROM.read(EEPROM_IP_ADDRESS+1) + "." +
(String)EEPROM.read(EEPROM_IP_ADDRESS+2) + "." +
(String)EEPROM.read(EEPROM_IP_ADDRESS+3));
}
if (server.hasArg("gwip"))
{
gateway_ip.fromString(server.arg("gwip"));
// make it persistent to eeprom
EEPROM.write(EEPROM_GW_ADDRESS, gateway_ip[0]);
EEPROM.write(EEPROM_GW_ADDRESS+1, gateway_ip[1]);
EEPROM.write(EEPROM_GW_ADDRESS+2, gateway_ip[2]);
EEPROM.write(EEPROM_GW_ADDRESS+3, gateway_ip[3]);
EEPROM.commit();
Serial.println("GW set to: " +
(String)EEPROM.read(EEPROM_GW_ADDRESS) + "." +
(String)EEPROM.read(EEPROM_GW_ADDRESS+1) + "." +
(String)EEPROM.read(EEPROM_GW_ADDRESS+2) + "." +
(String)EEPROM.read(EEPROM_GW_ADDRESS+3));
}
if (server.hasArg("netmas"))
{
subnet_mask.fromString(server.arg("netmas"));
// make it persistent to eeprom
EEPROM.write(EEPROM_NM_ADDRESS, subnet_mask[0]);
EEPROM.write(EEPROM_NM_ADDRESS+1, subnet_mask[1]);
EEPROM.write(EEPROM_NM_ADDRESS+2, subnet_mask[2]);
EEPROM.write(EEPROM_NM_ADDRESS+3, subnet_mask[3]);
EEPROM.commit();
Serial.println("NetMask set to: " +
(String)EEPROM.read(EEPROM_NM_ADDRESS) + "." +
(String)EEPROM.read(EEPROM_NM_ADDRESS+1) + "." +
(String)EEPROM.read(EEPROM_NM_ADDRESS+2) + "." +
(String)EEPROM.read(EEPROM_NM_ADDRESS+3));
}
if (server.hasArg("dns"))
{
dns.fromString(server.arg("dns"));
// make it persistent to eeprom
EEPROM.write(EEPROM_DNS_ADDRESS, dns[0]);
EEPROM.write(EEPROM_DNS_ADDRESS+1, dns[1]);
EEPROM.write(EEPROM_DNS_ADDRESS+2, dns[2]);
EEPROM.write(EEPROM_DNS_ADDRESS+3, dns[3]);
EEPROM.commit();
Serial.println("DNS set to: " +
(String)EEPROM.read(EEPROM_DNS_ADDRESS) + "." +
(String)EEPROM.read(EEPROM_DNS_ADDRESS+1) + "." +
(String)EEPROM.read(EEPROM_DNS_ADDRESS+2) + "." +
(String)EEPROM.read(EEPROM_DNS_ADDRESS+3));
}
// process the received data for every light
for (int light = 0; light < LIGHTS_COUNT; light++)
{
@ -461,7 +534,13 @@ String genLightControlHTML()
String replacePlaceholder(String http_content)
{
http_content.replace("{{VERSION_STR}}", (String)VERSION_STR);
http_content.replace("{{LIGHT_NAME}}", (String)LIGHT_NAME);
#ifdef DEVELOPMENT
http_content.replace("{{LIGHT_NAME_DEV_POSTFIX}}", (String)LIGHT_NAME_DEV_POSTFIX);
#else
http_content.replace("{{LIGHT_NAME_DEV_POSTFIX}}", (String)"&nbsp;");
#endif
http_content.replace("{{LIGHT_COUNT}}", (String)LIGHTS_COUNT);