Compare commits

...

27 commits

Author SHA1 Message Date
Kai Lauterbach 56254d58eb Updated binary files. 2023-05-13 23:02:06 +02:00
Kai Lauterbach c177404a75 Added a FSM to the main loop to prevent resets and improved performance. Added some comment v-lines. Improved readability of the code. 2023-05-13 23:01:34 +02:00
Kai Lauterbach 7e6dd20d31 Added color output to buttons after click. 2023-05-13 23:00:46 +02:00
Kai Lauterbach d336c047cb Splitted firmware main ino file into multiple separate files 2023-05-12 22:19:31 +02:00
Kai Lauterbach a9e8e2a778 Added main firmware and updated develop firmware bin file. 2023-05-12 12:25:31 +02:00
Kai Lauterbach 7452882ea7 process_lightdata function fixed - division by 0 was possible. 2023-05-12 12:23:45 +02:00
Kai Lauterbach 2e340d0cc8 Merge remote-tracking branch 'second/develop' 2023-05-12 12:20:55 +02:00
Kai Lauterbach 3f697e0b12 Updated main non-dev firmware bin file. 2023-05-12 07:22:47 +02:00
Kai Lauterbach 5f84840a00 Merge branch 'develop' 2023-05-12 07:20:08 +02:00
Kai Lauterbach 7855eaae38 Updated todays spiffs bin file 2023-05-11 19:41:00 +02:00
Kai Lauterbach 3914bfe57c Updated todays firmware binary. 2023-05-11 19:40:05 +02:00
Kai Lauterbach 06b61749ca Merge branch 'develop' 2023-05-11 19:38:14 +02:00
Kai Lauterbach acaacce737 Firmware updated, added latest bugfixes 2023-05-11 07:56:29 +02:00
Kai Lauterbach 0c7bae7b54 Merge branch 'develop' 2023-05-11 07:53:42 +02:00
Kai Lauterbach e01e46ef3b Added todays spiffs bin file 2023-05-10 15:08:02 +02:00
Kai Lauterbach 002275a67f Removed old spiffs from today first changes 2023-05-10 15:07:15 +02:00
Kai Lauterbach e680db96bd Merge branch 'develop' 2023-05-10 15:05:53 +02:00
Kai Lauterbach a2f70bf5ec Updated non-dev binary files. 2023-05-10 11:05:01 +02:00
Kai Lauterbach 2446632324 Merge branch 'develop' 2023-05-10 11:02:00 +02:00
Kai Lauterbach e7f0564ff0 Updated main branch webinterface content to the current development branch implementation. 2023-05-08 10:36:45 +02:00
Kai Lauterbach c802ed1b3c Merge branch 'develop' 2023-05-08 10:34:50 +02:00
Kai Lauterbach 90b6b36f26 Updated SPIFFS binary 2023-05-07 17:00:28 +02:00
Kai Lauterbach bc74f68e15 Merge branch 'develop' 2023-05-07 16:57:47 +02:00
Kai Lauterbach e7dbeac70b Updated firmware and spiffs binary files. 2023-05-07 07:58:40 +02:00
Kai Lauterbach 99e8a0fa82 Merge branch 'develop' 2023-05-07 07:53:41 +02:00
Kai Lauterbach 2025765fec Added primary bin files 2023-05-03 16:50:39 +02:00
Kai Lauterbach fc9baddfbd Removed development setting for main branch 2023-05-03 16:46:35 +02:00
12 changed files with 1111 additions and 1016 deletions

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 MiB

View file

@ -329,20 +329,24 @@ if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Disabled!";
button.style.backgroundColor = "green";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
button.style.backgroundColor = "";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
button.style.backgroundColor = "red";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
button.style.backgroundColor = "";
}, 2000);
showToast('Error while sending data to server.', 'error');
console.log('Error while sending data to server.');
@ -370,20 +374,24 @@ if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Enabled!";
button.style.backgroundColor = "green";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
button.style.backgroundColor = "";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
button.style.backgroundColor = "red";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
button.style.backgroundColor = "";
}, 2000);
showToast('Error while sending data to server.', 'error');
console.log('Error while sending data to server.');
@ -437,13 +445,13 @@ input.value = value;
input.style = "1px solod darkgray";
input.classList.add("pure-slider-range");
if (id.startsWith("ch1_")) {
input.style.background = "linear-gradient(to bottom, " + rgb2Hex(31, 119, 180) + ", white)";
input.style.background = "linear-gradient(to left, " + rgb2Hex(31, 119, 180) + ", white)";
} else if (id.startsWith("ch2_")) {
input.style.background = "linear-gradient(to bottom, " + rgb2Hex(255, 127, 14) + ", white)";
input.style.background = "linear-gradient(to left, " + rgb2Hex(255, 127, 14) + ", white)";
} else if (id.startsWith("ch3_")) {
input.style.background = "linear-gradient(to bottom, " + rgb2Hex(44, 160, 44) + ", white)";
input.style.background = "linear-gradient(to left, " + rgb2Hex(44, 160, 44) + ", white)";
} else if (id.startsWith("ch4_")) {
input.style.background = "linear-gradient(to bottom, " + rgb2Hex(214, 39, 40) + ", white)";
input.style.background = "linear-gradient(to left, " + rgb2Hex(214, 39, 40) + ", white)";
}
div = document.createElement("div");
div.appendChild(input);
@ -523,9 +531,11 @@ if (!jsonData) {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
button.style.backgroundColor = "red";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.style.backgroundColor = "";
button.innerHTML = "save";
}, 2000);
console.log('Error while generating timing control data.');
@ -542,20 +552,24 @@ if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Saved!";
button.style.backgroundColor = "green";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "save";
button.style.backgroundColor = "";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
button.style.backgroundColor = "red";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "save";
button.style.backgroundColor = "";
}, 2000);
showToast('Error while sending timing control data to server.', 'error');
console.log('Error while sending data to server.');

View file

@ -11,20 +11,24 @@ if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Enabled!";
button.style.backgroundColor = "green";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
button.style.backgroundColor = "";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
button.style.backgroundColor = "";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
button.style.backgroundColor = "";
}, 2000);
showToast('Error while sending data to server.', 'error');
console.log('Error while sending data to server.');
@ -49,20 +53,24 @@ if (xhr.status === 200) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Disabled!";
button.style.backgroundColor = "green";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
button.style.backgroundColor = "";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
button.style.backgroundColor = "red";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
button.style.backgroundColor = "";
}, 2000);
showToast('Error while sending data to server.', 'error');
console.log('Error while sending data to server.');

File diff suppressed because it is too large Load diff

View file

@ -383,20 +383,24 @@ links.forEach(function(link) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Disabled!";
button.style.backgroundColor = "green";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
button.style.backgroundColor = "";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
button.style.backgroundColor = "red";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
button.style.backgroundColor = "";
}, 2000);
showToast('Error while sending data to server.', 'error');
console.log('Error while sending data to server.');
@ -432,20 +436,24 @@ links.forEach(function(link) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Enabled!";
button.style.backgroundColor = "green";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
button.style.backgroundColor = "";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
button.style.backgroundColor = "red";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
button.style.backgroundColor = "";
}, 2000);
showToast('Error while sending data to server.', 'error');
console.log('Error while sending data to server.');
@ -520,13 +528,13 @@ function createSlider(id, max, value, step) {
input.classList.add("pure-slider-range");
// Change the color of the slider based on the id
if (id.startsWith("ch1_")) {
input.style.background = "linear-gradient(to bottom, " + rgb2Hex(31, 119, 180) + ", white)";
input.style.background = "linear-gradient(to left, " + rgb2Hex(31, 119, 180) + ", white)";
} else if (id.startsWith("ch2_")) {
input.style.background = "linear-gradient(to bottom, " + rgb2Hex(255, 127, 14) + ", white)";
input.style.background = "linear-gradient(to left, " + rgb2Hex(255, 127, 14) + ", white)";
} else if (id.startsWith("ch3_")) {
input.style.background = "linear-gradient(to bottom, " + rgb2Hex(44, 160, 44) + ", white)";
input.style.background = "linear-gradient(to left, " + rgb2Hex(44, 160, 44) + ", white)";
} else if (id.startsWith("ch4_")) {
input.style.background = "linear-gradient(to bottom, " + rgb2Hex(214, 39, 40) + ", white)";
input.style.background = "linear-gradient(to left, " + rgb2Hex(214, 39, 40) + ", white)";
}
div = document.createElement("div");
@ -642,9 +650,11 @@ function sendDataToServer() {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
button.style.backgroundColor = "red";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.style.backgroundColor = "";
button.innerHTML = "save";
}, 2000);
console.log('Error while generating timing control data.');
@ -662,20 +672,24 @@ function sendDataToServer() {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Saved!";
button.style.backgroundColor = "green";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "save";
button.style.backgroundColor = "";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
button.style.backgroundColor = "red";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "save";
button.style.backgroundColor = "";
}, 2000);
showToast('Error while sending timing control data to server.', 'error');
console.log('Error while sending data to server.');

View file

@ -12,20 +12,24 @@ links.forEach(function(link) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Enabled!";
button.style.backgroundColor = "green";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
button.style.backgroundColor = "";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
button.style.backgroundColor = "";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "ON";
button.style.backgroundColor = "";
}, 2000);
showToast('Error while sending data to server.', 'error');
console.log('Error while sending data to server.');
@ -53,20 +57,24 @@ links.forEach(function(link) {
button.classList.remove("pure-button-primary");
button.classList.add("success");
button.innerHTML = "Disabled!";
button.style.backgroundColor = "green";
setTimeout(function () {
button.classList.remove("success");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
button.style.backgroundColor = "";
}, 2000);
console.log('Data successfully sent to server!');
} else {
button.classList.remove("pure-button-primary");
button.classList.add("error");
button.innerHTML = "Error!";
button.style.backgroundColor = "red";
setTimeout(function () {
button.classList.remove("error");
button.classList.add("pure-button-primary");
button.innerHTML = "OFF";
button.style.backgroundColor = "";
}, 2000);
showToast('Error while sending data to server.', 'error');
console.log('Error while sending data to server.');

118
firmware/light_engine.ino Normal file
View file

@ -0,0 +1,118 @@
//********************************//
void apply_scene(uint8_t new_scene, uint8_t light)
{
if (new_scene == SCENE_RELEAX)
{
bri[light] = 144;
} else if (new_scene == SCENE_BRIGHT)
{
bri[light] = 254;
} else if (new_scene == SCENE_NIGHTLY)
{
bri[0] = 25;
bri[1] = 0;
bri[2] = 0;
bri[3] = 0;
}
}
//********************************//
void process_lightdata(uint8_t light, float tt)
{
if (tt <= 0)
{
tt = default_transitiontime;
}
if (light_state[light])
{
step_level[light] = (bri[light] - current_bri[light]) / tt;
} else {
step_level[light] = current_bri[light] / tt;
}
}
//********************************//
void lightEngine()
{
if (millis() < (last_lightengine_activity + TIME_LIGHTENGINE_INTERVAL_MS)) {
// abort processing, the transition setting is a delay of seconds
return;
}
last_lightengine_activity = millis();
for (int i = 0; i < LIGHTS_COUNT; i++)
{
if (light_state[i] == true)
{
if (bri[i] != current_bri[i])
{
in_transition = true;
current_bri[i] += step_level[i] / BRI_MOD_STEPS_PER_SEC;
if ((step_level[i] > 0.0 && current_bri[i] > bri[i]) ||
(step_level[i] < 0.0 && current_bri[i] < bri[i]))
{
current_bri[i] = bri[i];
//Serial.println("Reached target bri[" + (String)i + "] = " + (String)bri[i]);
}
uint16_t tmp_pwm = calcPWM(current_bri[i]);
current_pwm[i] = tmp_pwm;
//Serial.println("lon: pin" + (String)i + " = PWM(" + (String)tmp_pwm + ")");
analogWrite(pins[i], tmp_pwm);
}
} else { // light state is off
if (current_bri[i] != 0)
{
in_transition = true;
current_bri[i] -= step_level[i] / BRI_MOD_STEPS_PER_SEC;
if (current_bri[i] < 0)
{
current_bri[i] = 0;
//Serial.println("Reached target bri[" + (String)i + "] = " + (String)bri[i]);
}
uint16_t tmp_pwm = calcPWM(current_bri[i]);
current_pwm[i] = tmp_pwm;
//Serial.println("loff: pin" + (String)i + " = PWM(" + (String)tmp_pwm + ")");
analogWrite(pins[i], tmp_pwm);
}
}
} // for loop end
if (in_transition)
{
delay(6);
in_transition = false;
}
}
//********************************//
uint16_t calcPWM(float tbri)
{
uint16_t tmp_pwm = PWM_OFF;
if (tbri > 0.0)
{
tmp_pwm = PWM_MIN + (int)(tbri * BRI_TO_PWM_FACTOR);
}
if (tmp_pwm > PWM_MAX)
{
tmp_pwm = PWM_MAX;
}
return tmp_pwm;
}
//********************************//

225
firmware/test_pwm.ino Normal file
View file

@ -0,0 +1,225 @@
//********************************//
#define TEST_PWM_STATE_INIT 0
#define TEST_PWM_STATE_CH1_INC 1
#define TEST_PWM_STATE_CH1_DEC 2
#define TEST_PWM_STATE_CH2_INC 3
#define TEST_PWM_STATE_CH2_DEC 4
#define TEST_PWM_STATE_CH3_INC 5
#define TEST_PWM_STATE_CH3_DEC 6
#define TEST_PWM_STATE_CH4_INC 7
#define TEST_PWM_STATE_CH4_DEC 8
//********************************//
bool test_pwm = false;
uint32_t test_pwm_lastcheck_ms = 0;
uint8_t test_pwm_state = TEST_PWM_STATE_INIT;
//********************************//
void test_pwm_main()
{
if (test_pwm == false)
{
return;
} else if ((test_pwm_lastcheck_ms + PWM_TEST_INTERVA_MS) <= millis())
{
test_pwm_lastcheck_ms = millis();
switch (test_pwm_state)
{
// ----------------------- //
case TEST_PWM_STATE_INIT:
// disable the lights
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
{
light_state[i] = false;
bri[i] = 0;
current_bri[i] = 0;
current_pwm[i] = 0;
transitiontime[i] = 0;
process_lightdata(i, transitiontime[i]);
}
light_state[0] = true;
test_pwm_state = TEST_PWM_STATE_CH1_INC;
break;
// ----------------------- //
case TEST_PWM_STATE_CH1_INC:
if (bri[0] < 255)
{
bri[0] += TEST_PWM_CHG_CNT;
transitiontime[0] = 1;
process_lightdata(0, transitiontime[0]);
} else {
test_pwm_state = TEST_PWM_STATE_CH1_DEC;
}
break;
case TEST_PWM_STATE_CH1_DEC:
if (bri[0] > 0)
{
bri[0] -= TEST_PWM_CHG_CNT;
transitiontime[0] = 1;
process_lightdata(0, transitiontime[0]);
} else {
light_state[0] = false;
bri[0] = 0;
current_bri[0] = 0;
current_pwm[0] = 0;
transitiontime[0] = default_transitiontime;
process_lightdata(0, transitiontime[0]);
light_state[1] = true;
test_pwm_state = TEST_PWM_STATE_CH2_INC;
}
break;
// ----------------------- //
case TEST_PWM_STATE_CH2_INC:
if (bri[1] < 255)
{
bri[1] += TEST_PWM_CHG_CNT;
transitiontime[1] = 1;
process_lightdata(1, transitiontime[1]);
} else {
test_pwm_state = TEST_PWM_STATE_CH2_DEC;
}
break;
case TEST_PWM_STATE_CH2_DEC:
if (bri[1] > 0)
{
bri[1] -= TEST_PWM_CHG_CNT;
transitiontime[1] = 1;
process_lightdata(1, transitiontime[1]);
} else {
light_state[1] = false;
bri[1] = 0;
current_bri[1] = 0;
current_pwm[1] = 0;
transitiontime[1] = default_transitiontime;
process_lightdata(1, transitiontime[1]);
light_state[2] = true;
test_pwm_state = TEST_PWM_STATE_CH3_INC;
}
break;
// ----------------------- //
case TEST_PWM_STATE_CH3_INC:
if (bri[2] < 255)
{
bri[2] += TEST_PWM_CHG_CNT;
transitiontime[2] = 1;
process_lightdata(2, transitiontime[2]);
} else {
test_pwm_state = TEST_PWM_STATE_CH3_DEC;
}
break;
case TEST_PWM_STATE_CH3_DEC:
if (bri[2] > 0)
{
bri[2] -= TEST_PWM_CHG_CNT;
transitiontime[2] = 1;
process_lightdata(2, transitiontime[2]);
} else {
light_state[2] = false;
bri[2] = 0;
current_bri[2] = 0;
current_pwm[2] = 0;
transitiontime[2] = default_transitiontime;
process_lightdata(2, transitiontime[2]);
light_state[3] = true;
test_pwm_state = TEST_PWM_STATE_CH4_INC;
}
break;
// ----------------------- //
case TEST_PWM_STATE_CH4_INC:
if (bri[3] < 255)
{
bri[3] += TEST_PWM_CHG_CNT;
transitiontime[3] = 1;
process_lightdata(3, transitiontime[3]);
} else {
test_pwm_state = TEST_PWM_STATE_CH4_DEC;
}
break;
case TEST_PWM_STATE_CH4_DEC:
if (bri[3] > 0)
{
bri[3] -= TEST_PWM_CHG_CNT;
transitiontime[3] = 1;
process_lightdata(3, transitiontime[3]);
} else {
test_pwm = false;
tc_enabled = tc_enabled_old;
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
{
light_state[i] = false;
bri[i] = 0;
current_bri[i] = 0;
current_pwm[i] = 0;
transitiontime[i] = default_transitiontime;
process_lightdata(i, transitiontime[i]);
}
tc_reset();
tc_update_main(); // load the tc if required
test_pwm_state = TEST_PWM_STATE_INIT;
}
break;
// ----------------------- //
default:
test_pwm_state = TEST_PWM_STATE_INIT;
}
Serial.println("---");
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
{
Serial.println("light_state[" + (String)i + "] = " + (String)light_state[i]);
Serial.println("bri[" + (String)i + "] = " + (String)bri[i]);
Serial.println("current_bri[" + (String)i + "] = " + (String)current_bri[i]);
Serial.println("current_pwm[" + (String)i + "] = " + (String)current_pwm[i]);
Serial.println("transitiontime[" + (String)i + "] = " + (String)transitiontime[i]);
}
}
}
//********************************//

View file

@ -180,14 +180,15 @@ void tc_update_main()
// no new predecessor or successor found, start over
current_target_data_block = 255;
Serial.println("No predecessor or successor found, start over...");
// disable the lights
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
{
light_state[i] = false;
bri[i] = 0;
current_bri[i] = 0;
current_pwm[i] = 0;
transitiontime[i] = 0;
transitiontime[i] = default_transitiontime;
process_lightdata(i, transitiontime[i]);
}
@ -207,10 +208,15 @@ void tc_update_main()
if (target_data_block >= NUMBER_OF_TIMER_DATA_BLOCKS)
{
// we are not between two valid data points, do nothing
// TODO check if setting all lights to false is correct here
Serial.println("tdb is >= num data blocks, abort operation...");
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
{
light_state[i] = false;
light_state[i] = false;
bri[i] = 0;
current_bri[i] = 0;
current_pwm[i] = 0;
transitiontime[i] = default_transitiontime;
process_lightdata(i, transitiontime[i]);
}
target_data_block = 255;
current_target_data_block = 255;
@ -233,7 +239,7 @@ void tc_update_main()
}
Serial.println("-----\ntdb = " + (String)target_data_block);
Serial.print("target time: ");
Serial.print("target dataset time: ");
Serial.print(tc_data[target_data_block].hh);
Serial.print(":");
Serial.print(tc_data[target_data_block].mm);
@ -271,13 +277,9 @@ void tc_update_main()
}
// enable the lights
light_state[0] = true;
light_state[1] = true;
light_state[2] = true;
light_state[3] = true;
for (uint8_t i = 0; i < LIGHTS_COUNT; i++)
{
light_state[i] = true;
Serial.println("light_state[" + (String)i + "] = " + (String)light_state[i]);
}

618
firmware/webserver.ino Normal file
View file

@ -0,0 +1,618 @@
//********************************//
void handleNotFound()
{
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++)
{
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
}
//********************************//
void init_webserver()
{
// -------------------- //
server.on("/state", HTTP_PUT, []()
{ // HTTP PUT request used to set a new light state
DynamicJsonDocument root(512);
DeserializationError error = deserializeJson(root, server.arg("plain"));
if (error) {
server.send(404, "text/plain", "FAIL. " + server.arg("plain"));
} else {
for (JsonPair state : root.as<JsonObject>())
{
const char* key = state.key().c_str();
int light = atoi(key) - 1;
if (light < 0)
{
light = 0;
} else if (light > (LIGHTS_COUNT-1))
{
light = (LIGHTS_COUNT-1);
}
JsonObject values = state.value();
uint8_t tmp = EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS);
if (values.containsKey("on"))
{
if (values["on"])
{
light_state[light] = true;
if (tmp == LAST_STATE_STARTUP_LIGHT_LAST_STATE && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == LIGHT_STATE_OFF)
{
EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_ON);
}
} else {
light_state[light] = false;
if (tmp == LAST_STATE_STARTUP_LIGHT_LAST_STATE && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == LIGHT_STATE_ON)
{
EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_OFF);
}
}
}
if (values.containsKey("bri"))
{
bri[light] = values["bri"];
}
if (values.containsKey("bri_inc"))
{
bri[light] += (int)values["bri_inc"];
if (bri[light] > 255) bri[light] = 255;
else if (bri[light] < 1) bri[light] = 1;
}
if (values.containsKey("transitiontime"))
{
default_transitiontime = values["transitiontime"];
if (default_transitiontime <= 0)
{
default_transitiontime = 1;
}
if (tc_enabled == TIMING_CONTROL_DISABLED)
{
for (uint8_t i = 0 ; i < LIGHTS_COUNT; i++)
{
// set the default transition time for all lights
process_lightdata(i, default_transitiontime);
}
}
}
}
String output;
serializeJson(root, output);
server.send(200, "text/plain", output);
}
});
// -------------------- //
server.on("/state", HTTP_GET, []()
{ // HTTP GET request used to fetch current light state
uint8_t light = server.arg("light").toInt() - 1;
if (light < 0)
{
light = 0;
} else if (light > (LIGHTS_COUNT-1))
{
light = (LIGHTS_COUNT-1);
}
DynamicJsonDocument root(512);
root["on"] = light_state[light];
root["bri"] = bri[light];
root["curbri"] = (int)current_bri[light];
root["curpwm"] = current_pwm[light];
String output;
serializeJson(root, output);
server.send(200, "text/plain", output);
});
// -------------------- //
server.on("/detect", []()
{ // HTTP GET request used to discover the light type
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["lights"] = LIGHTS_COUNT;
root["protocol"] = "native_multi";
root["modelid"] = "LWB010";
root["type"] = "dimmable_light";
root["mac"] = String(macString);
root["version"] = LIGHT_VERSION;
String output;
serializeJson(root, output);
server.send(200, "text/plain", output);
});
// -------------------- //
server.on("/test_pwm", []()
{
test_pwm = true;
tc_enabled_old = tc_enabled;
tc_enabled = TIMING_CONTROL_DISABLED;
server.send(200, "text/html", "OK");
});
// -------------------- //
server.on("/tc_data_blocks_read", []()
{
String output = tc_getJsonData();
server.send(200, "application/json", output);
});
// -------------------- //
server.on("/tc_data_blocks_store", []()
{
if (server.hasArg("data"))
{
String jsonData = server.arg("data");
Serial.println("Received: " + jsonData);
tc_jsonDataBlocksToEEPROM(jsonData);
server.send(200, "text/html", "tcdata saved");
}
});
// -------------------- //
server.on("/js_top", []()
{
server.send(200, "text/html", replacePlaceholder(loadSPIFFSFile("/top.js")));
});
// -------------------- //
server.on("/js_bottom", []()
{
server.send(200, "text/html", replacePlaceholder(loadSPIFFSFile("/bottom.js")));
});
// -------------------- //
server.on("/css", []()
{
server.send(200, "text/css", loadSPIFFSFile("/style.css"));
});
// -------------------- //
server.on("/", []()
{
if (server.hasArg("transition"))
{
default_transitiontime = server.arg("transition").toFloat();
if (default_transitiontime <= 0)
{
default_transitiontime = 1;
}
if (tc_enabled == TIMING_CONTROL_DISABLED)
{
for (uint8_t i = 0 ; i < LIGHTS_COUNT; i++)
{
// set the default transition time for all lights
process_lightdata(i, default_transitiontime);
Serial.println("transition for light " + (String)i + " set to " + (String)default_transitiontime);
}
}
}
// startup behavior switch handling
if (server.hasArg("startup"))
{
int startup = server.arg("startup").toInt();
if (EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS) != startup)
{
EEPROM.write(EEPROM_LAST_STATE_STARTUP_ADDRESS, startup);
for (uint8_t i = 0; i < LIGHTS_COUNT; i++) {
uint8_t tmp = (light_state[i] == true ? LIGHT_STATE_ON : LIGHT_STATE_OFF);
if (EEPROM.read(EEPROM_LAST_STATE_ADDRESS + i) != tmp)
{
EEPROM.write(EEPROM_LAST_STATE_ADDRESS + i, tmp);
}
}
EEPROM.commit();
Serial.print("Startup behavior set to ");
Serial.println(EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS));
}
}
// timing controller switch handling
if (server.hasArg("tc"))
{
if (server.arg("tc") == "true")
{
if (tc_enabled == TIMING_CONTROL_DISABLED)
{
if (EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS) != TIMING_CONTROL_ENABLED)
{
tc_enabled = TIMING_CONTROL_ENABLED;
EEPROM.write(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS, TIMING_CONTROL_ENABLED);
EEPROM.commit();
Serial.print("Timing control = ");
Serial.println(EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS));
tc_update_main(); // call the main update function to read data and set the light states
}
}
} else { // tc is set to false or something else
if (tc_enabled == TIMING_CONTROL_ENABLED)
{
tc_enabled = TIMING_CONTROL_DISABLED;
if (EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS) != TIMING_CONTROL_DISABLED)
{
EEPROM.write(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS, TIMING_CONTROL_DISABLED);
EEPROM.commit();
Serial.print("Timing control = ");
Serial.println(EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS));
for (uint8_t i = 0 ; i < LIGHTS_COUNT; i++)
{
// set the default transition time for all lights
process_lightdata(i, default_transitiontime);
}
}
}
}
}
// scene switch handling
if (server.hasArg("scene"))
{
scene = server.arg("scene").toInt();
if (EEPROM.read(EEPROM_SCENE_ADDRESS) != scene)
{
EEPROM.write(EEPROM_SCENE_ADDRESS, scene);
EEPROM.commit();
Serial.print("Scene set to ");
Serial.println(EEPROM.read(EEPROM_SCENE_ADDRESS));
}
}
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)
{
EEPROM.write(EEPROM_DYNAMIC_IP_ADDRESS, tmp2);
EEPROM.commit();
Serial.print("Set dynamic IP to ");
Serial.println(EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS));
}
}
// process the received data for every light
for (int light = 0; light < LIGHTS_COUNT; light++)
{
if (server.hasArg("bri" + (String)light))
{
int tmp = (int)server.arg("bri" + (String)light).toInt();
if (tmp > 255)
{
tmp = 255;
} else if (tmp < 0) {
tmp = 0;
}
bri[light] = tmp;
Serial.print("Brightness ");
Serial.print(light);
Serial.print(" set to ");
Serial.println(bri[light]);
}
if (server.hasArg("on" + (String)light))
{
uint8_t tmp = EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS);
if (server.arg("on" + (String)light) == "true" && light_state[light] == false)
{
light_state[light] = true;
if (tmp == 0 && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == 0)
{
EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_ON);
EEPROM.commit();
}
Serial.print("Light ");
Serial.print(light);
Serial.print(" state set to ");
Serial.println(light_state[light]);
} else if (server.arg("on" + (String)light) == "false" && light_state[light] == true)
{
light_state[light] = false;
bri[light] = 0;
if (tmp == 0 && EEPROM.read(EEPROM_LAST_STATE_ADDRESS + light) == 1)
{
EEPROM.write(EEPROM_LAST_STATE_ADDRESS + light, LIGHT_STATE_OFF);
EEPROM.commit();
}
Serial.print("Light ");
Serial.print(light);
Serial.print(" state set to ");
Serial.println(light_state[light]);
}
if (tc_enabled == TIMING_CONTROL_DISABLED)
{
process_lightdata(light, default_transitiontime);
}
} else {
// light is off
if (tc_enabled == TIMING_CONTROL_DISABLED)
{
process_lightdata(light, default_transitiontime);
}
}
// start alerting for every light
if (server.hasArg("alert"))
{
if (light_state[light])
{
current_bri[light] = 0;
} else {
current_bri[light] = 255;
}
}
} // process all lights
if (server.hasArg("resettc"))
{ // reqrite the tc config and reboot
tc_write_default();
ESP.reset();
}
if (server.hasArg("reset"))
{
ESP.reset();
}
// ***** Generate static HTML page ***** //
String tmp1 = genHMTLTop();
String tmp2 = genLightControlHTML();
String tmp3 = getIndexHTMLMiddle();
String tmp4 = genConfigHTML();
String tmp5 = genHMTLBottom();
server.send(200, "text/html", tmp1 + tmp2 + tmp3 + tmp4 + tmp5);
});
// -------------------- //
server.on("/reset", []()
{ // trigger manual reset
server.send(200, "text/html", "reset");
delay(1000);
ESP.restart();
});
server.onNotFound(handleNotFound);
}
//********************************//
String genHMTLTop()
{
return replacePlaceholder(getIndexHTMLTop());
}
String genHMTLBottom()
{
return replacePlaceholder(getIndexHTMLBottom());
}
String genConfigHTML()
{
// +++++ Generate config part of the page +++++
return replacePlaceholder(getConfigHTML());
}
String genTCEditHTML()
{
return replacePlaceholder(getTCDataEditHTML());
}
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)
{
http_content.replace("{{LIGHT_NAME}}", (String)LIGHT_NAME);
http_content.replace("{{LIGHT_COUNT}}", (String)LIGHTS_COUNT);
int tc_val = EEPROM.read(EEPROM_TIMING_CONTROL_ENABLED_ADDRESS);
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}}", "");
}
http_content.replace("{{TRANSITION_TIME}}", (String)default_transitiontime);
int ls_val = EEPROM.read(EEPROM_LAST_STATE_STARTUP_ADDRESS);
if (ls_val == LAST_STATE_STARTUP_LIGHT_LAST_STATE)
{
http_content.replace("{{STARTUP_SELECTED_LS_0}}", "selected=\"selected\"");
} else {
http_content.replace("{{STARTUP_SELECTED_LS_0}}", "");
}
if (ls_val == LAST_STATE_STARTUP_LIGHT_ON_STATE)
{
http_content.replace("{{STARTUP_SELECTED_ON_1}}", "selected=\"selected\"");
} else {
http_content.replace("{{STARTUP_SELECTED_ON_1}}", "");
}
if (ls_val == LAST_STATE_STARTUP_LIGHT_OFF_STATE)
{
http_content.replace("{{STARTUP_SELECTED_OFF_2}}", "selected=\"selected\"");
} else {
http_content.replace("{{STARTUP_SELECTED_OFF_2}}", "");
}
// scene
int sc_val = EEPROM.read(EEPROM_SCENE_ADDRESS);
if (sc_val == SCENE_RELEAX)
{
http_content.replace("{{SCENE_SELECTED_RELAX_0}}", "selected=\"selected\"");
} else {
http_content.replace("{{SCENE_SELECTED_RELAX_0}}", "");
}
if (sc_val == SCENE_BRIGHT)
{
http_content.replace("{{SCENE_SELECTED_BRIGHT_1}}", "selected=\"selected\"");
} else {
http_content.replace("{{SCENE_SELECTED_BRIGHT_1}}", "");
}
if (sc_val == SCENE_NIGHTLY)
{
http_content.replace("{{SCENE_SELECTED_NIGHT_2}}", "selected=\"selected\"");
} else {
http_content.replace("{{SCENE_SELECTED_NIGHT_2}}", "");
}
// Wifi settings
http_content.replace("{{WIFI_SSID}}", WiFi.SSID());
// Network settings
uint8_t dip = EEPROM.read(EEPROM_DYNAMIC_IP_ADDRESS);
if (dip)
{
http_content.replace("{{DIP_LINK_ON_PRIMARY}}", "pure-button-primary");
http_content.replace("{{DIP_LINK_OFF_PRIMARY}}", "");
} else {
http_content.replace("{{DIP_LINK_OFF_PRIMARY}}", "pure-button-primary");
http_content.replace("{{DIP_LINK_ON_PRIMARY}}", "");
}
// network config
http_content.replace("{{WIFI_CFG_IP}}", WiFi.localIP().toString());
http_content.replace("{{WIFI_CFG_GW}}", WiFi.gatewayIP().toString());
http_content.replace("{{WIFI_CFG_NM}}", WiFi.subnetMask().toString());
http_content.replace("{{WIFI_CFG_DNS}}", WiFi.dnsIP().toString());
// add the current ip address to the page
http_content.replace("{{IP_ADDRESS}}", WiFi.localIP().toString());
// set the pwm values
http_content.replace("{{PWM_MIN}}", (String)PWM_MIN);
http_content.replace("{{PWM_MAX}}", (String)PWM_MAX);
return http_content;
}
//********************************//
String loadSPIFFSFile(String fname)
{
File file = SPIFFS.open(fname, "r");
if (!file)
{
Serial.println("Failed to open file " + fname);
return "";
}
String contents = file.readString();
file.close();
return contents;
}
//********************************//
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 getTCDataEditHTML()
{
// load file
return loadSPIFFSFile("/tc_data_edit.html");
}
//********************************//
String getLightControlHTML()
{
// load file
return loadSPIFFSFile("/light_control_template.html");
}
//********************************//