diff --git a/src/core/led.cpp b/src/core/led.cpp
index 28de6180c..e56a41143 100644
--- a/src/core/led.cpp
+++ b/src/core/led.cpp
@@ -16,317 +16,317 @@
* along with this program. If not, see .
*/
- #include "led.h"
- #include "emsesp.h"
-
- namespace emsesp {
-
- uuid::log::Logger LED::logger_{F_(led), uuid::log::Facility::KERN};
-
- // initialise the LED, fetching the settings from the WebSettingsService
- // set the LED to on or off when in normal operating mode
- void LED::init() {
- // copy the application settings
- EMSESP::webSettingsService.read([&](WebSettings & settings) {
- led_gpio_ = settings.led_gpio;
- led_type_ = settings.led_type;
- hide_led_ = settings.hide_led;
- });
-
- if (!led_gpio_) { // 0 means disabled
- LOG_INFO("LED disabled");
- return;
- }
-
- // for safety
- if (!led_type_) {
- pinMode(led_gpio_, OUTPUT);
- }
-
- reset_led(); // start with LED in default state, depending on if it's hidden or not
- }
-
- // handle LED routine
- // called from the System::loop()
- // returns true if the LED flash is active, i.e its a lock down state
- bool LED::loop(uint8_t healthcheck, bool button_busy) {
- // if LED flashing is active it means its about to perform a factory reset, so don't do anything else and keep it flashing
- if (led_fast_flash_timer_) {
- led_fast_flash();
- return true;
- }
-
- // the user-requested LED blink always has preference
- if (!is_user_led_blink_) {
- // check for button press.
- // while the button is held show the LED (yellow on RGB LED, on/off on standard LED),
- // and on release go back to the default state and re-check the health on the next cycle
- if (last_button_busy_ != button_busy) {
- last_button_busy_ = button_busy;
- if (button_busy) {
- set_led(Color::YELLOW); // Yellow
- } else {
- reset_led();
- previous_healthcheck_ = System::HEALTHCHECK_RESET;
- }
- return false;
- }
-
- // check the system health.
- // Set the sequence accordingly, only if the healthcheck is not 0 and has changed
- if (healthcheck != previous_healthcheck_) {
- previous_healthcheck_ = healthcheck;
- color_steps_[0] = Color::OFF;
- color_steps_[1] = Color::OFF;
- color_steps_[2] = Color::OFF;
-
- // if the healthcheck is 0, i.e. system is healthy, reset the LED
- if (healthcheck == 0) {
- reset_led();
- return false;
- }
-
- // 1 flash (blue) is the EMS bus is not connected
- // 2 flashes (red, red) if the network (wifi or ethernet) is not connected
- // 3 flashes (red, red, blue) is both the bus and the network are not connected
- bool no_network = (healthcheck & System::HEALTHCHECK_NO_NETWORK) == System::HEALTHCHECK_NO_NETWORK;
- bool no_bus = (healthcheck & System::HEALTHCHECK_NO_BUS) == System::HEALTHCHECK_NO_BUS;
-
- // set step 1
- if (no_network) {
- color_steps_[0] = Color::RED; // red, no network
- } else if (no_bus) {
- color_steps_[0] = Color::BLUE; // blue, no bus
- }
-
- // set step 2
- if (no_network) {
- color_steps_[1] = Color::RED; // red, no network
- }
-
- // set step 3
- if (no_network && no_bus) {
- color_steps_[2] = Color::BLUE; // blue, no network and no bus
- }
- }
-
- // there's nothing to flash, so leave the LED in the state reset_led() gave it.
- // Running the sequence here would keep writing Color::OFF and a healthy system would never show green.
- if (healthcheck == 0 || button_busy) {
- return false;
- }
- }
-
- // show the LED status based on the healthcheck and button busy status
- sequence_led();
-
- return false;
- }
-
- // turn the LED back it's default state depending on if it's hidden or not
- void LED::reset_led() {
- is_user_led_blink_ = false;
- set_led(hide_led_ ? Color::OFF : Color::GREEN); // Green
- color_steps_[0] = Color::OFF;
- color_steps_[1] = Color::OFF;
- color_steps_[2] = Color::OFF;
-
- // rewind the sequence so it starts from the top if the health degrades again
- led_long_timer_ = 1; // 1 will kick it off immediately
- led_short_timer_ = 0;
- led_flash_step_ = 0;
- }
-
- // LED flash every few ms and then perform a factory reset
- void LED::led_fast_flash() {
- uint32_t current_time = uuid::get_uptime();
-
- if (current_time - last_toggle_time_ >= LED_FLASH_INTERVAL_MS) {
- led_flash_state_ = !led_flash_state_;
- last_toggle_time_ = current_time;
- set_led(led_flash_state_ ? Color::YELLOW : Color::OFF); // Yellow
- }
-
- // after duration, turn off the LED, and call the format command
- if (current_time - led_flash_start_time_ >= led_flash_duration_) {
- set_led(Color::OFF);
- led_fast_flash_timer_ = false;
- #ifndef EMSESP_DEBUG
- System::command_format(nullptr, 0); // Execute format operation, unless in debug mode
- #endif
- }
- }
-
- // set LED on/off or RGB color
- // ignores whether the LED is hidden or not (if hide_led_ is set)
- void LED::set_led(Color color) {
- if (!led_gpio_) {
- return;
- }
-
- // RGB lookup table indexed by Color enum (must match enum order in led.h)
- static constexpr uint8_t B = RGB_LED_BRIGHTNESS;
- static constexpr uint8_t H = RGB_LED_BRIGHTNESS / 2;
- static constexpr uint8_t rgb_table[][3] = {
- {0, 0, 0}, // OFF
- {B, B, B}, // ON (white)
- {B, 0, 0}, // RED
- {0, B, 0}, // GREEN
- {0, 0, B}, // BLUE
- {B, B, 0}, // YELLOW
- {B, H, 0}, // ORANGE
- {0, B, B}, // CYAN
- {H, 0, H} // PINK
- };
-
- const uint8_t color_idx = static_cast(color);
- const uint8_t idx = (color_idx < sizeof(rgb_table) / sizeof(rgb_table[0])) ? color_idx : static_cast(Color::OFF);
- const uint8_t red = rgb_table[idx][0];
- const uint8_t green = rgb_table[idx][1];
- const uint8_t blue = rgb_table[idx][2];
-
- if (led_type_) {
- rgbLedWrite(led_gpio_, red, green, blue);
- } else {
- digitalWrite(led_gpio_, (red == 0 && green == 0 && blue == 0) || color == Color::OFF ? !LED_ON : LED_ON);
- }
- }
-
- // set LED custom routine
- // For example: /api/system/led?data=red:blink1
- // For older non-RGB models, the colour would default to just being on.
- bool LED::set_custom_led_routine(std::string color, std::string pattern) {
- static constexpr struct {
- const char * name;
- Color value;
- } color_map[] = {
- {"off", Color::OFF},
- {"on", Color::ON},
- {"white", Color::ON},
- {"red", Color::RED},
- {"green", Color::GREEN},
- {"blue", Color::BLUE},
- {"yellow", Color::YELLOW},
- {"orange", Color::ORANGE},
- {"cyan", Color::CYAN},
- {"pink", Color::PINK},
- };
-
- Color color_type = Color::OFF;
- bool color_matched = false;
- for (const auto & entry : color_map) {
- if (color == entry.name) {
- color_type = entry.value;
- color_matched = true;
- break;
- }
- }
- if (!color_matched) {
- return false;
- }
-
- // reset the color steps
- color_steps_[0] = Color::OFF;
- color_steps_[1] = Color::OFF;
- color_steps_[2] = Color::OFF;
-
- // blink patterns
- if (pattern == "blink1") {
- color_steps_[0] = color_type;
- } else if (pattern == "blink2") {
- color_steps_[0] = color_type;
- color_steps_[1] = color_type;
- } else if (pattern == "blink3") {
- color_steps_[0] = color_type;
- color_steps_[1] = color_type;
- color_steps_[2] = color_type;
-
- // special patterns, ignores the user color
- } else if (pattern == "rgb") {
- color_steps_[0] = Color::RED;
- color_steps_[1] = Color::GREEN;
- color_steps_[2] = Color::BLUE;
- } else if (pattern == "cpc") {
- color_steps_[0] = Color::CYAN;
- color_steps_[1] = Color::PINK;
- color_steps_[2] = Color::CYAN;
- } else {
- return false; // pattern not recognized
- }
-
- is_user_led_blink_ = true; // user routine is active
-
- // when this is called we want the sequence_led to restart immediately and skip the long pause
- led_long_timer_ = uuid::get_uptime() + HEALTHCHECK_LED_FLASH_FAST_DURATION + 200UL;
-
- return true;
- }
-
- // uses LED to show system health and user-requested LED blinks
- // it works in a batch of 3 configured flashes, then a long pause
- // the timing is different for user-requested LED blink and for system healthcheck
- void LED::sequence_led() {
- // first long pause before we start flashing
- auto current_time = uuid::get_uptime();
- if (led_long_timer_
- && (uint32_t)(current_time - led_long_timer_) >= (is_user_led_blink_ ? HEALTHCHECK_LED_LONG_FAST_DURATION : HEALTHCHECK_LED_LONG_DURATION)) {
- led_short_timer_ = current_time; // start the short timer
- led_long_timer_ = 0; // stop long timer
- led_flash_step_ = 1; // enable the short flash timer
- }
-
- // the flash timer which starts after the long pause
- if (led_flash_step_
- && (uint32_t)(current_time - led_short_timer_) >= (is_user_led_blink_ ? HEALTHCHECK_LED_FLASH_FAST_DURATION : HEALTHCHECK_LED_FLASH_DURATION)) {
- led_long_timer_ = 0; // stop the long timer
- led_short_timer_ = current_time;
-
- if (++led_flash_step_ == 8) {
- // finished first iteration, reset the whole sequence, turn off LED
- led_long_timer_ = uuid::get_uptime();
- led_flash_step_ = 0;
- set_led(Color::OFF); // turn off the LED
-
- // if we're running a user-requested LED blink, turn it off and go back to the healthcheck sequence
- if (is_user_led_blink_) {
- is_user_led_blink_ = false;
- previous_healthcheck_ = System::HEALTHCHECK_RESET; // this will force the healthcheck to be checked again
- }
- return;
- }
-
- if (led_flash_step_ % 2) {
- // handle the three step events (on odd numbers 3,5,7 etc). see if we need to set a LED color
- switch (led_flash_step_) {
- case 3: // first flash
- set_led(color_steps_[0]);
- break;
- case 5: // second flash
- set_led(color_steps_[1]);
- break;
- case 7: // third flash
- set_led(color_steps_[2]);
- break;
- default:
- break;
- }
- } else {
- set_led(Color::OFF); // turn off on even number count, to make it flash
- }
- }
- }
-
- // Start the LED flash timer - duration in seconds
- void LED::start_led_fast_flash(uint8_t duration) {
- // Don't start if already running
- if (led_fast_flash_timer_) {
- return;
- }
-
- // Reset counter and state
- led_flash_start_time_ = uuid::get_uptime(); // current time
- led_flash_duration_ = (uint32_t)duration * 1000; // duration in milliseconds
- led_fast_flash_timer_ = true; // it's active
- }
-
- } // namespace emsesp
\ No newline at end of file
+#include "led.h"
+#include "emsesp.h"
+
+namespace emsesp {
+
+uuid::log::Logger LED::logger_{F_(led), uuid::log::Facility::KERN};
+
+// initialise the LED, fetching the settings from the WebSettingsService
+// set the LED to on or off when in normal operating mode
+void LED::init() {
+ // copy the application settings
+ EMSESP::webSettingsService.read([&](WebSettings & settings) {
+ led_gpio_ = settings.led_gpio;
+ led_type_ = settings.led_type;
+ hide_led_ = settings.hide_led;
+ });
+
+ if (!led_gpio_) { // 0 means disabled
+ LOG_INFO("LED disabled");
+ return;
+ }
+
+ // for safety
+ if (!led_type_) {
+ pinMode(led_gpio_, OUTPUT);
+ }
+
+ reset_led(); // start with LED in default state, depending on if it's hidden or not
+}
+
+// handle LED routine
+// called from the System::loop()
+// returns true if the LED flash is active, i.e its a lock down state
+bool LED::loop(uint8_t healthcheck, bool button_busy) {
+ // if LED flashing is active it means its about to perform a factory reset, so don't do anything else and keep it flashing
+ if (led_fast_flash_timer_) {
+ led_fast_flash();
+ return true;
+ }
+
+ // the user-requested LED blink always has preference
+ if (!is_user_led_blink_) {
+ // check for button press.
+ // while the button is held show the LED (yellow on RGB LED, on/off on standard LED),
+ // and on release go back to the default state and re-check the health on the next cycle
+ if (last_button_busy_ != button_busy) {
+ last_button_busy_ = button_busy;
+ if (button_busy) {
+ set_led(Color::YELLOW); // Yellow
+ } else {
+ reset_led();
+ previous_healthcheck_ = System::HEALTHCHECK_RESET;
+ }
+ return false;
+ }
+
+ // check the system health.
+ // Set the sequence accordingly, only if the healthcheck is not 0 and has changed
+ if (healthcheck != previous_healthcheck_) {
+ previous_healthcheck_ = healthcheck;
+ color_steps_[0] = Color::OFF;
+ color_steps_[1] = Color::OFF;
+ color_steps_[2] = Color::OFF;
+
+ // if the healthcheck is 0, i.e. system is healthy, reset the LED
+ if (healthcheck == 0) {
+ reset_led();
+ return false;
+ }
+
+ // 1 flash (blue) is the EMS bus is not connected
+ // 2 flashes (red, red) if the network (wifi or ethernet) is not connected
+ // 3 flashes (red, red, blue) is both the bus and the network are not connected
+ bool no_network = (healthcheck & System::HEALTHCHECK_NO_NETWORK) == System::HEALTHCHECK_NO_NETWORK;
+ bool no_bus = (healthcheck & System::HEALTHCHECK_NO_BUS) == System::HEALTHCHECK_NO_BUS;
+
+ // set step 1
+ if (no_network) {
+ color_steps_[0] = Color::RED; // red, no network
+ } else if (no_bus) {
+ color_steps_[0] = Color::BLUE; // blue, no bus
+ }
+
+ // set step 2
+ if (no_network) {
+ color_steps_[1] = Color::RED; // red, no network
+ }
+
+ // set step 3
+ if (no_network && no_bus) {
+ color_steps_[2] = Color::BLUE; // blue, no network and no bus
+ }
+ }
+
+ // there's nothing to flash, so leave the LED in the state reset_led() gave it.
+ // Running the sequence here would keep writing Color::OFF and a healthy system would never show green.
+ if (healthcheck == 0 || button_busy) {
+ return false;
+ }
+ }
+
+ // show the LED status based on the healthcheck and button busy status
+ sequence_led();
+
+ return false;
+}
+
+// turn the LED back it's default state depending on if it's hidden or not
+void LED::reset_led() {
+ is_user_led_blink_ = false;
+ set_led(hide_led_ ? Color::OFF : Color::GREEN); // Green
+ color_steps_[0] = Color::OFF;
+ color_steps_[1] = Color::OFF;
+ color_steps_[2] = Color::OFF;
+
+ // rewind the sequence so it starts from the top if the health degrades again
+ led_long_timer_ = 1; // 1 will kick it off immediately
+ led_short_timer_ = 0;
+ led_flash_step_ = 0;
+}
+
+// LED flash every few ms and then perform a factory reset
+void LED::led_fast_flash() {
+ uint32_t current_time = uuid::get_uptime();
+
+ if (current_time - last_toggle_time_ >= LED_FLASH_INTERVAL_MS) {
+ led_flash_state_ = !led_flash_state_;
+ last_toggle_time_ = current_time;
+ set_led(led_flash_state_ ? Color::YELLOW : Color::OFF); // Yellow
+ }
+
+ // after duration, turn off the LED, and call the format command
+ if (current_time - led_flash_start_time_ >= led_flash_duration_) {
+ set_led(Color::OFF);
+ led_fast_flash_timer_ = false;
+#ifndef EMSESP_DEBUG
+ System::command_format(nullptr, 0); // Execute format operation, unless in debug mode
+#endif
+ }
+}
+
+// set LED on/off or RGB color
+// ignores whether the LED is hidden or not (if hide_led_ is set)
+void LED::set_led(Color color) {
+ if (!led_gpio_) {
+ return;
+ }
+
+ // RGB lookup table indexed by Color enum (must match enum order in led.h)
+ static constexpr uint8_t B = RGB_LED_BRIGHTNESS;
+ static constexpr uint8_t H = RGB_LED_BRIGHTNESS / 2;
+ static constexpr uint8_t rgb_table[][3] = {
+ {0, 0, 0}, // OFF
+ {B, B, B}, // ON (white)
+ {B, 0, 0}, // RED
+ {0, B, 0}, // GREEN
+ {0, 0, B}, // BLUE
+ {B, B, 0}, // YELLOW
+ {B, H, 0}, // ORANGE
+ {0, B, B}, // CYAN
+ {H, 0, H} // PINK
+ };
+
+ const uint8_t color_idx = static_cast(color);
+ const uint8_t idx = (color_idx < sizeof(rgb_table) / sizeof(rgb_table[0])) ? color_idx : static_cast(Color::OFF);
+ const uint8_t red = rgb_table[idx][0];
+ const uint8_t green = rgb_table[idx][1];
+ const uint8_t blue = rgb_table[idx][2];
+
+ if (led_type_) {
+ rgbLedWrite(led_gpio_, red, green, blue);
+ } else {
+ digitalWrite(led_gpio_, (red == 0 && green == 0 && blue == 0) || color == Color::OFF ? !LED_ON : LED_ON);
+ }
+}
+
+// set LED custom routine
+// For example: /api/system/led?data=red:blink1
+// For older non-RGB models, the colour would default to just being on.
+bool LED::set_custom_led_routine(std::string color, std::string pattern) {
+ static constexpr struct {
+ const char * name;
+ Color value;
+ } color_map[] = {
+ {"off", Color::OFF},
+ {"on", Color::ON},
+ {"white", Color::ON},
+ {"red", Color::RED},
+ {"green", Color::GREEN},
+ {"blue", Color::BLUE},
+ {"yellow", Color::YELLOW},
+ {"orange", Color::ORANGE},
+ {"cyan", Color::CYAN},
+ {"pink", Color::PINK},
+ };
+
+ Color color_type = Color::OFF;
+ bool color_matched = false;
+ for (const auto & entry : color_map) {
+ if (color == entry.name) {
+ color_type = entry.value;
+ color_matched = true;
+ break;
+ }
+ }
+ if (!color_matched) {
+ return false;
+ }
+
+ // reset the color steps
+ color_steps_[0] = Color::OFF;
+ color_steps_[1] = Color::OFF;
+ color_steps_[2] = Color::OFF;
+
+ // blink patterns
+ if (pattern == "blink1") {
+ color_steps_[0] = color_type;
+ } else if (pattern == "blink2") {
+ color_steps_[0] = color_type;
+ color_steps_[1] = color_type;
+ } else if (pattern == "blink3") {
+ color_steps_[0] = color_type;
+ color_steps_[1] = color_type;
+ color_steps_[2] = color_type;
+
+ // special patterns, ignores the user color
+ } else if (pattern == "rgb") {
+ color_steps_[0] = Color::RED;
+ color_steps_[1] = Color::GREEN;
+ color_steps_[2] = Color::BLUE;
+ } else if (pattern == "cpc") {
+ color_steps_[0] = Color::CYAN;
+ color_steps_[1] = Color::PINK;
+ color_steps_[2] = Color::CYAN;
+ } else {
+ return false; // pattern not recognized
+ }
+
+ is_user_led_blink_ = true; // user routine is active
+
+ // when this is called we want the sequence_led to restart immediately and skip the long pause
+ led_long_timer_ = uuid::get_uptime() + HEALTHCHECK_LED_FLASH_FAST_DURATION + 200UL;
+
+ return true;
+}
+
+// uses LED to show system health and user-requested LED blinks
+// it works in a batch of 3 configured flashes, then a long pause
+// the timing is different for user-requested LED blink and for system healthcheck
+void LED::sequence_led() {
+ // first long pause before we start flashing
+ auto current_time = uuid::get_uptime();
+ if (led_long_timer_
+ && (uint32_t)(current_time - led_long_timer_) >= (is_user_led_blink_ ? HEALTHCHECK_LED_LONG_FAST_DURATION : HEALTHCHECK_LED_LONG_DURATION)) {
+ led_short_timer_ = current_time; // start the short timer
+ led_long_timer_ = 0; // stop long timer
+ led_flash_step_ = 1; // enable the short flash timer
+ }
+
+ // the flash timer which starts after the long pause
+ if (led_flash_step_
+ && (uint32_t)(current_time - led_short_timer_) >= (is_user_led_blink_ ? HEALTHCHECK_LED_FLASH_FAST_DURATION : HEALTHCHECK_LED_FLASH_DURATION)) {
+ led_long_timer_ = 0; // stop the long timer
+ led_short_timer_ = current_time;
+
+ if (++led_flash_step_ == 8) {
+ // finished first iteration, reset the whole sequence, turn off LED
+ led_long_timer_ = uuid::get_uptime();
+ led_flash_step_ = 0;
+ set_led(Color::OFF); // turn off the LED
+
+ // if we're running a user-requested LED blink, turn it off and go back to the healthcheck sequence
+ if (is_user_led_blink_) {
+ is_user_led_blink_ = false;
+ previous_healthcheck_ = System::HEALTHCHECK_RESET; // this will force the healthcheck to be checked again
+ }
+ return;
+ }
+
+ if (led_flash_step_ % 2) {
+ // handle the three step events (on odd numbers 3,5,7 etc). see if we need to set a LED color
+ switch (led_flash_step_) {
+ case 3: // first flash
+ set_led(color_steps_[0]);
+ break;
+ case 5: // second flash
+ set_led(color_steps_[1]);
+ break;
+ case 7: // third flash
+ set_led(color_steps_[2]);
+ break;
+ default:
+ break;
+ }
+ } else {
+ set_led(Color::OFF); // turn off on even number count, to make it flash
+ }
+ }
+}
+
+// Start the LED flash timer - duration in seconds
+void LED::start_led_fast_flash(uint8_t duration) {
+ // Don't start if already running
+ if (led_fast_flash_timer_) {
+ return;
+ }
+
+ // Reset counter and state
+ led_flash_start_time_ = uuid::get_uptime(); // current time
+ led_flash_duration_ = (uint32_t)duration * 1000; // duration in milliseconds
+ led_fast_flash_timer_ = true; // it's active
+}
+
+} // namespace emsesp
\ No newline at end of file