[LED] Refactor LED handling (#2051)
Refactor LED handling into a library Use a task instead of relying on the loop for precise timing Co-authored-by: Florian <1technophile@users.noreply.github.com>
This commit is contained in:
1 parent
20af9ccf11
commit
435b8ca3d9
14 files changed
+932
-437
No files matched your search
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
Theengs LEDManager - We Unite Sensors in One Open-Source Interface
|
||||
|
||||
Copyright: (c)Florian ROBERT
|
||||
|
||||
This file is part of LEDManager library.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "LEDManager.h"
|
||||
|
||||
LEDManager::LEDManager() : globalBrightness(255) {}
|
||||
|
||||
void LEDManager::addLEDStrip(int pin, int numLeds) {
|
||||
LEDStrip ledStrip;
|
||||
ledStrip.pin = pin;
|
||||
#ifdef LED_ADDRESSABLE
|
||||
ledStrip.strip = new Adafruit_NeoPixel(numLeds, pin, NEO_GRB + NEO_KHZ800);
|
||||
ledStrip.strip->begin();
|
||||
ledStrip.strip->show();
|
||||
ledStrip.strip->setBrightness(globalBrightness);
|
||||
#else
|
||||
pinMode(pin, OUTPUT);
|
||||
#endif
|
||||
|
||||
ledStrip.ledStates.resize(numLeds, {OFF, OFF, 0, 0, 0, 0, 0, false, 255, FADE_AMOUNT, {OFF, 0, -1, false}});
|
||||
|
||||
ledStrips.push_back(ledStrip);
|
||||
}
|
||||
|
||||
void LEDManager::setMode(int stripIndex, int ledIndex, Mode mode, uint32_t color, int durationOrBlinkCount) {
|
||||
if (stripIndex >= 0 && stripIndex < ledStrips.size()) {
|
||||
if (ledIndex == -1) {
|
||||
for (int i = 0; i < ledStrips[stripIndex].ledStates.size(); i++) {
|
||||
setModeForSingleLED(stripIndex, i, mode, color, durationOrBlinkCount);
|
||||
}
|
||||
} else if (ledIndex >= 0 && ledIndex < ledStrips[stripIndex].ledStates.size()) {
|
||||
setModeForSingleLED(stripIndex, ledIndex, mode, color, durationOrBlinkCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LEDManager::setModeForSingleLED(int stripIndex, int ledIndex, Mode mode, uint32_t color, int durationOrBlinkCount) {
|
||||
auto& state = ledStrips[stripIndex].ledStates[ledIndex];
|
||||
|
||||
if ((state.mode == BLINK || state.mode == PULSE) && state.durationOrBlinkCount > 0) {
|
||||
state.queuedState = {mode, color, durationOrBlinkCount, true};
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode != BLINK && mode != PULSE) {
|
||||
state.previousMode = state.mode;
|
||||
state.previousColor = state.color;
|
||||
}
|
||||
state.mode = mode;
|
||||
state.color = color;
|
||||
state.durationOrBlinkCount = durationOrBlinkCount;
|
||||
state.lastUpdateTime = millis();
|
||||
state.blinkCounter = 0;
|
||||
state.isBlinkOn = false;
|
||||
state.brightness = globalBrightness;
|
||||
state.fadeAmount = FADE_AMOUNT;
|
||||
state.queuedState.isQueued = false;
|
||||
}
|
||||
|
||||
void LEDManager::setBrightness(uint8_t brightness) {
|
||||
#ifdef LED_ADDRESSABLE
|
||||
globalBrightness = brightness;
|
||||
for (auto& ledStrip : ledStrips) {
|
||||
ledStrip.strip->setBrightness(brightness);
|
||||
for (auto& state : ledStrip.ledStates) {
|
||||
state.brightness = brightness;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LEDManager::setLEDColor(int stripIndex, int ledIndex, uint32_t color) {
|
||||
if (stripIndex < 0 || stripIndex >= ledStrips.size()) return;
|
||||
if (ledIndex < 0 || ledIndex >= ledStrips[stripIndex].ledStates.size()) return;
|
||||
|
||||
uint8_t r, g, b;
|
||||
extractRGB(color, r, g, b);
|
||||
|
||||
r = (r * globalBrightness) / 255;
|
||||
g = (g * globalBrightness) / 255;
|
||||
b = (b * globalBrightness) / 255;
|
||||
|
||||
#ifdef LED_ADDRESSABLE
|
||||
ledStrips[stripIndex].strip->setPixelColor(ledIndex, r, g, b);
|
||||
ledStrips[stripIndex].strip->show();
|
||||
#else
|
||||
// For non-addressable LEDs, we'll use the first LED of each strip
|
||||
if (ledIndex == 0) {
|
||||
int pin = ledStrips[stripIndex].pin;
|
||||
analogWrite(pin, (r + g + b) / 3); // Average of RGB for single-color LED
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LEDManager::update() {
|
||||
for (int stripIndex = 0; stripIndex < ledStrips.size(); stripIndex++) {
|
||||
for (int ledIndex = 0; ledIndex < ledStrips[stripIndex].ledStates.size(); ledIndex++) {
|
||||
auto& state = ledStrips[stripIndex].ledStates[ledIndex];
|
||||
switch (state.mode) {
|
||||
case BLINK:
|
||||
handleBlink(stripIndex, ledIndex);
|
||||
break;
|
||||
case PULSE:
|
||||
handlePulse(stripIndex, ledIndex);
|
||||
break;
|
||||
case STATIC:
|
||||
handleStatic(stripIndex, ledIndex);
|
||||
break;
|
||||
case OFF:
|
||||
setLEDColor(stripIndex, ledIndex, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef LED_ADDRESSABLE
|
||||
ledStrips[stripIndex].strip->show();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void LEDManager::handleBlink(int stripIndex, int ledIndex) {
|
||||
auto& state = ledStrips[stripIndex].ledStates[ledIndex];
|
||||
unsigned long currentTime = millis();
|
||||
if (currentTime - state.lastUpdateTime >= BLINK_INTERVAL) {
|
||||
state.lastUpdateTime = currentTime;
|
||||
if (state.durationOrBlinkCount > 0) {
|
||||
if (state.blinkCounter == 0) {
|
||||
state.blinkCounter = state.durationOrBlinkCount * 2;
|
||||
} else {
|
||||
state.blinkCounter--;
|
||||
if (state.blinkCounter == 0) {
|
||||
if (state.queuedState.isQueued) {
|
||||
applyQueuedState(stripIndex, ledIndex);
|
||||
} else {
|
||||
returnToPreviousState(stripIndex, ledIndex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state.isBlinkOn = !state.isBlinkOn;
|
||||
if (state.isBlinkOn) {
|
||||
setLEDColor(stripIndex, ledIndex, state.color);
|
||||
} else {
|
||||
setLEDColor(stripIndex, ledIndex, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LEDManager::handlePulse(int stripIndex, int ledIndex) {
|
||||
auto& state = ledStrips[stripIndex].ledStates[ledIndex];
|
||||
unsigned long currentTime = millis();
|
||||
if (currentTime - state.lastUpdateTime >= PULSE_INTERVAL) {
|
||||
state.lastUpdateTime = currentTime;
|
||||
state.brightness += state.fadeAmount;
|
||||
if (state.brightness <= 0 || state.brightness >= 255) {
|
||||
state.fadeAmount = -state.fadeAmount;
|
||||
state.brightness = constrain(state.brightness, 0, 255);
|
||||
if (state.durationOrBlinkCount > 0) {
|
||||
state.durationOrBlinkCount--;
|
||||
if (state.durationOrBlinkCount == 0) {
|
||||
if (state.queuedState.isQueued) {
|
||||
applyQueuedState(stripIndex, ledIndex);
|
||||
} else {
|
||||
returnToPreviousState(stripIndex, ledIndex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint32_t adjustedColor = (state.color & 0xFF000000) |
|
||||
(((state.color & 0x00FF0000) * state.brightness / 255) & 0x00FF0000) |
|
||||
(((state.color & 0x0000FF00) * state.brightness / 255) & 0x0000FF00) |
|
||||
(((state.color & 0x000000FF) * state.brightness / 255) & 0x000000FF);
|
||||
setLEDColor(stripIndex, ledIndex, adjustedColor);
|
||||
}
|
||||
}
|
||||
|
||||
void LEDManager::handleStatic(int stripIndex, int ledIndex) {
|
||||
auto& state = ledStrips[stripIndex].ledStates[ledIndex];
|
||||
unsigned long currentTime = millis();
|
||||
if (state.durationOrBlinkCount > 0) {
|
||||
if (currentTime - state.lastUpdateTime >= static_cast<unsigned long>(state.durationOrBlinkCount) * 1000) {
|
||||
if (state.queuedState.isQueued) {
|
||||
applyQueuedState(stripIndex, ledIndex);
|
||||
} else {
|
||||
returnToPreviousState(stripIndex, ledIndex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
setLEDColor(stripIndex, ledIndex, state.color);
|
||||
}
|
||||
|
||||
void LEDManager::returnToPreviousState(int stripIndex, int ledIndex) {
|
||||
auto& state = ledStrips[stripIndex].ledStates[ledIndex];
|
||||
state.mode = state.previousMode;
|
||||
state.color = state.previousColor;
|
||||
state.durationOrBlinkCount = -1; // Set to infinite for the previous state
|
||||
state.lastUpdateTime = millis();
|
||||
state.blinkCounter = 0;
|
||||
state.isBlinkOn = false;
|
||||
state.brightness = globalBrightness;
|
||||
state.fadeAmount = FADE_AMOUNT;
|
||||
}
|
||||
|
||||
void LEDManager::applyQueuedState(int stripIndex, int ledIndex) {
|
||||
auto& state = ledStrips[stripIndex].ledStates[ledIndex];
|
||||
state.mode = state.queuedState.mode;
|
||||
state.color = state.queuedState.color;
|
||||
state.durationOrBlinkCount = state.queuedState.durationOrBlinkCount;
|
||||
state.lastUpdateTime = millis();
|
||||
state.blinkCounter = 0;
|
||||
state.isBlinkOn = false;
|
||||
state.brightness = globalBrightness;
|
||||
state.fadeAmount = FADE_AMOUNT;
|
||||
state.queuedState.isQueued = false;
|
||||
}
|
||||
|
||||
void LEDManager::extractRGB(uint32_t color, uint8_t& r, uint8_t& g, uint8_t& b) {
|
||||
r = (color >> 16) & 0xFF;
|
||||
g = (color >> 8) & 0xFF;
|
||||
b = color & 0xFF;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
Theengs LEDManager - We Unite Sensors in One Open-Source Interface
|
||||
|
||||
Copyright: (c)Florian ROBERT
|
||||
|
||||
This file is part of LEDManager library.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#ifndef LED_MANAGER_H
|
||||
#define LED_MANAGER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef LED_ADDRESSABLE
|
||||
# include <Adafruit_NeoPixel.h>
|
||||
#endif
|
||||
|
||||
#ifndef BLINK_INTERVAL
|
||||
# define BLINK_INTERVAL 500
|
||||
#endif
|
||||
|
||||
#ifndef PULSE_INTERVAL
|
||||
# define PULSE_INTERVAL 30
|
||||
#endif
|
||||
|
||||
#ifndef FADE_AMOUNT
|
||||
# define FADE_AMOUNT 5
|
||||
#endif
|
||||
|
||||
// Define the pins for the RGB LED power if needed
|
||||
#ifndef LED_ADDRESSABLE_POWER
|
||||
# define LED_ADDRESSABLE_POWER -1
|
||||
#endif
|
||||
|
||||
class LEDManager {
|
||||
public:
|
||||
enum Mode { OFF,
|
||||
STATIC,
|
||||
BLINK,
|
||||
PULSE };
|
||||
|
||||
LEDManager();
|
||||
void init();
|
||||
void addLEDStrip(int pin, int numLeds);
|
||||
void setMode(int stripIndex, int ledIndex, Mode mode, uint32_t color, int durationOrBlinkCount = -1);
|
||||
void update();
|
||||
void setBrightness(uint8_t brightness);
|
||||
|
||||
private:
|
||||
struct QueuedState {
|
||||
Mode mode;
|
||||
uint32_t color;
|
||||
int durationOrBlinkCount;
|
||||
bool isQueued;
|
||||
};
|
||||
|
||||
struct LEDState {
|
||||
Mode mode;
|
||||
Mode previousMode;
|
||||
uint32_t color;
|
||||
uint32_t previousColor;
|
||||
int durationOrBlinkCount;
|
||||
unsigned long lastUpdateTime;
|
||||
int blinkCounter;
|
||||
bool isBlinkOn;
|
||||
int brightness;
|
||||
int fadeAmount;
|
||||
QueuedState queuedState;
|
||||
};
|
||||
|
||||
struct LEDStrip {
|
||||
#ifdef LED_ADDRESSABLE
|
||||
Adafruit_NeoPixel* strip;
|
||||
#endif
|
||||
int pin;
|
||||
std::vector<LEDState> ledStates;
|
||||
};
|
||||
|
||||
std::vector<LEDStrip> ledStrips;
|
||||
int globalBrightness;
|
||||
|
||||
void setModeForSingleLED(int stripIndex, int ledIndex, Mode mode, uint32_t color, int durationOrBlinkCount);
|
||||
void setLEDColor(int stripIndex, int ledIndex, uint32_t color);
|
||||
void handleBlink(int stripIndex, int ledIndex);
|
||||
void handlePulse(int stripIndex, int ledIndex);
|
||||
void handleStatic(int stripIndex, int ledIndex);
|
||||
void returnToPreviousState(int stripIndex, int ledIndex);
|
||||
void applyQueuedState(int stripIndex, int ledIndex);
|
||||
void extractRGB(uint32_t color, uint8_t& r, uint8_t& g, uint8_t& b);
|
||||
};
|
||||
|
||||
#endif // LED_MANAGER_H
|
||||
@@ -0,0 +1,132 @@
|
||||
# LEDManager Library
|
||||
|
||||
## Overview
|
||||
|
||||
The LEDManager library provides a flexible and easy-to-use interface for controlling LEDs in projects. It supports both addressable LED strips and individual non-addressable LEDs, offering various modes of operation such as static, blinking, and pulsing. The library is designed to work seamlessly with PlatformIO and can be easily configured using build flags.
|
||||
|
||||
## Features
|
||||
|
||||
- Support for both addressable LED strips and individual non-addressable LEDs
|
||||
- Multiple operation modes: OFF, STATIC, BLINK, and PULSE
|
||||
- Individual control of LEDs within each strip (for addressable LEDs)
|
||||
- Global brightness control
|
||||
- Queueing of LED states for complex sequences
|
||||
- Automatic return to previous state after temporary modes
|
||||
- Compatible with PlatformIO build flags for easy configuration
|
||||
- Customizable color schemes
|
||||
|
||||
## Installation
|
||||
|
||||
1. Clone this repository or download the ZIP file.
|
||||
2. Extract the contents to your PlatformIO project's `lib` directory.
|
||||
|
||||
## Configuration
|
||||
|
||||
Configure the LEDManager library using build flags in your `platformio.ini` file:
|
||||
|
||||
```ini
|
||||
build_flags =
|
||||
; For addressable LEDs:
|
||||
-DLED_ADDRESSABLE=true
|
||||
; For non-addressable LEDs, comment out the line above
|
||||
|
||||
; Optional timing configurations:
|
||||
-DBLINK_INTERVAL=500
|
||||
-DPULSE_INTERVAL=30
|
||||
-DFADE_AMOUNT=5
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Here's a basic example of how to use the LEDManager library:
|
||||
|
||||
```cpp
|
||||
#include "LEDManager.h"
|
||||
|
||||
LEDManager ledManager;
|
||||
|
||||
void setup() {
|
||||
|
||||
#ifdef LED_ADDRESSABLE
|
||||
ledManager.addLEDStrip(5, 30); // Add addressable LED strip on pin 5 with 30 LEDs
|
||||
#else
|
||||
ledManager.addLEDStrip(5, 1); // Add non-addressable LED on pin 5
|
||||
ledManager.addLEDStrip(6, 1); // Add non-addressable LED on pin 6
|
||||
#endif
|
||||
|
||||
ledManager.setBrightness(128); // Set global brightness to 50%
|
||||
}
|
||||
|
||||
void loop() {
|
||||
#ifdef LED_ADDRESSABLE
|
||||
// Set all LEDs on the strip to static green
|
||||
ledManager.setMode(0, -1, LEDManager::STATIC, LED_COLOR_GREEN);
|
||||
|
||||
// Blink first 5 LEDs red for 3 times
|
||||
for (int i = 0; i < 5; i++) {
|
||||
ledManager.setMode(0, i, LEDManager::BLINK, LED_COLOR_RED, 3);
|
||||
}
|
||||
#else
|
||||
// Set first LED to static green
|
||||
ledManager.setMode(0, 0, LEDManager::STATIC, LED_COLOR_GREEN);
|
||||
|
||||
// Blink second LED red
|
||||
ledManager.setMode(1, 0, LEDManager::BLINK, LED_COLOR_RED, 3);
|
||||
#endif
|
||||
|
||||
ledManager.update();
|
||||
delay(100);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Initialization and Setup
|
||||
|
||||
```cpp
|
||||
LEDManager ledManager;
|
||||
ledManager.addLEDStrip(int pin, int numLeds);
|
||||
```
|
||||
|
||||
### Setting LED Mode
|
||||
|
||||
```cpp
|
||||
ledManager.setMode(int stripIndex, int ledIndex, Mode mode, uint32_t color, int durationOrBlinkCount = -1);
|
||||
```
|
||||
|
||||
- `stripIndex`: Index of the LED strip (0-based)
|
||||
- `ledIndex`: LED index within the strip (0-based) or -1 for all LEDs in the strip (addressable LEDs only)
|
||||
- `mode`: `LEDManager::OFF`, `LEDManager::STATIC`, `LEDManager::BLINK`, or `LEDManager::PULSE`
|
||||
- `color`: Color value (use predefined colors from LEDColorDefinitions.h or custom 24-bit RGB values)
|
||||
- `durationOrBlinkCount`: Duration for STATIC mode (in milliseconds), blink/pulse count for BLINK/PULSE modes (-1 for infinite)
|
||||
|
||||
### Setting Brightness
|
||||
|
||||
```cpp
|
||||
ledManager.setBrightness(brightness);
|
||||
```
|
||||
|
||||
- `brightness`: Global brightness value (0-255)
|
||||
|
||||
### Updating LEDs
|
||||
|
||||
Call this method in your main loop to update LED states:
|
||||
|
||||
```cpp
|
||||
ledManager.update();
|
||||
```
|
||||
## Advanced Configuration
|
||||
|
||||
You can customize the behavior of the LEDManager by defining the following build flags:
|
||||
|
||||
- `BLINK_INTERVAL`: Sets the interval (in milliseconds) between blink states (default: 500)
|
||||
- `PULSE_INTERVAL`: Sets the interval (in milliseconds) between pulse updates (default: 30)
|
||||
- `FADE_AMOUNT`: Sets the increment/decrement value for pulsing (default: 5)
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions to the LEDManager library are welcome! Please feel free to submit a Pull Request.
|
||||
|
||||
## License
|
||||
|
||||
This library is released under the LGPL V3 License.
|
||||
Reference in new issue
Block a user