Skip to content

Commit c84e481

Browse files
committed
**core**:
- Upgraded to *espressif32 v6.12.0* **color-light firmware**: - Added `leds-mod` configuration option. If set to *true* a module for each LED pixel will be created to allow direct control of each LED pixel. - Fixed bug in the *Control.Toggle* command. - Fixed *AudioLight* flag persistency.
1 parent 394a829 commit c84e481

14 files changed

Lines changed: 117 additions & 93 deletions

File tree

examples/color-light/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ In addition to default system options the following configuration options are av
1414
| `leds-pin` | LED strip GPIO pin number | -1 (-1=not used) |
1515
| `leds-cnt` | Number of LEDs | 1 (1 - 200) |
1616
| `leds-spd` | Data transfer speed | 0 (0=800kHz, 256=400kHz) |
17+
| `leds-mod` | Add a module for each LED | false |
1718
| `stld-pin` | Status LED (RGB) pin | -1 (-1=not used) |
1819
| `stld-typ` | Status LED type | RGB/RGBW order mask (see code for ref.) |
1920
| `stld-spd` | Status LED speed | 0 (0=800kHz, 256=400kHz) |

examples/color-light/StatusLed.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ class StatusLed: Task {
8989
colorLight = new ColorLight(IO::IOEventDomains::HomeAutomation_HomeGenie, COLOR_LIGHT_ADDRESS, "Color Light");
9090
colorLight->module->setProperty(Implements::Scheduling, "true");
9191
colorLight->module->setProperty(Implements::Scheduling_ModuleEvents, "true");
92-
colorLight->module->setProperty(Preference::AudioLight, "true");
9392

9493
colorLight->onSetColor([this](LightColor c) {
9594
if (statusLED != nullptr) {

examples/color-light/color-fx.h

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,34 +46,31 @@ void fx_init(int count, LightColor& currentColor) {
4646
}
4747
}
4848

49-
void fx_reset(Adafruit_NeoPixel* pixels, LightColor& color) {
49+
void fx_reset(LightColor& color) {
5050
// hueOffset = 0;
5151
hueZoom = 1;
5252
}
5353

54-
void fx_solid(Adafruit_NeoPixel* pixels, LightColor& color, int transitionMs = 200) {
55-
if (pixels == nullptr) return;
56-
57-
for (int i = 0; i < pixels->numPixels(); i++) {
54+
void fx_solid(uint16_t ledsCount, LightColor& color, int transitionMs = 200) {
55+
for (int i = 0; i < ledsCount; i++) {
5856
animatedColors[i]->setColor(color.getHue(), color.getSaturation(), color.getValue(), transitionMs);
5957
}
6058
}
6159

6260
float currentSaturation;
6361
float cursorDirection = 1;
6462
unsigned long rainbow_refresh_ts = 0;
65-
void fx_rainbow(Adafruit_NeoPixel* pixels, LightColor& color, float iterations = 1) {
66-
if (pixels == nullptr || millis() - rainbow_refresh_ts <= 100) return;
63+
void fx_rainbow(uint16_t ledsCount, LightColor& color, float iterations = 1) {
64+
if (millis() - rainbow_refresh_ts <= 100) return;
6765

68-
uint numPixels = pixels->numPixels();
6966
currentSaturation = color.getSaturation();
70-
float length = numPixels * hueZoom;
67+
float length = ledsCount * hueZoom;
7168

7269
float hueStep = 1.0f / (float) length * iterations;
7370

7471
float v = color.getValue();
75-
for (int i = 0; i < numPixels; i++) {
76-
float inc = (i < numPixels / iterations ? (float)i : (float)(numPixels - i)) * hueStep;
72+
for (int i = 0; i < ledsCount; i++) {
73+
float inc = (i < ledsCount / iterations ? (float)i : (float)(ledsCount - i)) * hueStep;
7774
float h = FX_DEG_NORM((color.getHue() + hueOffset) + inc);
7875
animatedColors[i]->setColor(h, currentSaturation, v, currentSaturation * 100);
7976
}
@@ -99,11 +96,10 @@ int stripe_step = 3;
9996
float stripe_cycle = 0;
10097
float stripe_previous_hue;
10198

102-
void fx_white_stripes(Adafruit_NeoPixel* pixels, LightColor& color, bool brightWhite = false) {
103-
if (pixels == nullptr || millis() - stripe_refresh_ts <= stripe_delay) return;
99+
void fx_white_stripes(uint16_t ledsCount, LightColor& color, bool brightWhite = false) {
100+
if (millis() - stripe_refresh_ts <= stripe_delay) return;
104101

105-
uint numPixels = pixels->numPixels();
106-
int stripe_length = (int)round((float)numPixels / 5.0f);
102+
int stripe_length = (int)round((float)ledsCount / 5.0f);
107103
float shift;
108104

109105
if (stripe_length <= stripe_step) stripe_length = stripe_step * 2;
@@ -116,13 +112,13 @@ void fx_white_stripes(Adafruit_NeoPixel* pixels, LightColor& color, bool brightW
116112
cursorDirection = (color.getHue() - stripe_previous_hue > 0) ? 1 : -1;
117113
stripe_previous_hue = color.getHue();
118114

119-
for (int i = 0; i < numPixels; i++) {
115+
for (int i = 0; i < ledsCount; i++) {
120116
float v = color.getValue();
121117
float s = color.getSaturation();
122118
if ((int)round(i + shift) % stripe_length < stripe_step) {
123119
// draw stripe
124120
animatedColors[i]->setColor(0, 0, brightWhite && v > 0 ? 1 : v,
125-
(float)stripe_transition / numPixels);
121+
(float)stripe_transition / ledsCount);
126122
} else {
127123
// draw solid color
128124
animatedColors[i]->setColor(color.getHue(), s, v,
@@ -137,10 +133,10 @@ void fx_white_stripes(Adafruit_NeoPixel* pixels, LightColor& color, bool brightW
137133
unsigned long kaleidoscope_refresh_ts = 0;
138134
int kaleidoscope_delay = 500;
139135

140-
void fx_kaleidoscope(Adafruit_NeoPixel* pixels, LightColor& color) {
141-
if (pixels == nullptr || millis() - kaleidoscope_refresh_ts <= kaleidoscope_delay) return;
136+
void fx_kaleidoscope(uint16_t ledsCount, LightColor& color) {
137+
if (millis() - kaleidoscope_refresh_ts <= kaleidoscope_delay) return;
142138

143-
for (int i = 0; i < pixels->numPixels(); i++) {
139+
for (int i = 0; i < ledsCount; i++) {
144140
float rnd1 = random(1000);
145141
float rnd2 = random(1000);
146142
if ((int)rnd1 % 2 == 0) {

examples/color-light/color-light.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,15 @@ void setup() {
3636
auto miniModule = homeGenie->getDefaultModule();
3737
miniModule->name = "LED Controller";
3838

39-
// Read stored config
39+
// Read stored config (common)
4040
ledsPin = (int16_t)Config::getSetting(Configuration::LedsPin).toInt();
41-
pixelsType = (int16_t)Config::getSetting(Configuration::LedsType).toInt();
42-
pixelsSpeed = (int16_t)Config::getSetting(Configuration::LedsSpeed).toInt();
4341
// the following settings can also be configured from the app
4442
ledsCount = abs(Config::getSetting(Configuration::LedsCount).toInt());
4543
maxPower = Config::getSetting(Configuration::LedsPower).toInt();
4644
if (maxPower <= 0) maxPower = DEFAULT_MAX_POWER;
45+
// NeoPixels WS2810B RGB LED config
46+
pixelsType = (int16_t)Config::getSetting(Configuration::LedsType).toInt();
47+
pixelsSpeed = (int16_t)Config::getSetting(Configuration::LedsSpeed).toInt();
4748

4849
// Add UI options to configure this device using the app
4950
setupControllerOptions(miniModule);
@@ -70,7 +71,7 @@ void setup() {
7071
// colorLight is the main control module
7172
colorLight->onSetColor([](LightColor color) {
7273
statusLed.setCurrentColor(color);
73-
fx_reset(pixels, color);
74+
fx_reset(color);
7475
});
7576

7677
auto module = colorLight->module;
@@ -123,34 +124,33 @@ void loop()
123124
// Strobe tick ON: show strobe light for `strobeFxDurationMs` milliseconds (25)
124125
auto c = LightColor();
125126
c.setColor(0, 0, 1, 0);
126-
fx_solid(pixels, c, 0);
127+
fx_solid(ledsCount, c, 0);
127128
strobeOff = false;
128129

129130
} else {
130131

131132
// Apply selected effect (FX.Style)
132133

133134
auto currentColor = statusLed.getCurrentColor();
134-
// apply selected light style
135135
switch (currentStyleIndex) {
136136
case LightStyles::RAINBOW:
137-
fx_rainbow(pixels, currentColor, 1);
137+
fx_rainbow(ledsCount, currentColor, 1);
138138
break;
139139
case LightStyles::RAINBOW_2:
140-
fx_rainbow(pixels, currentColor, 2);
140+
fx_rainbow(ledsCount, currentColor, 2);
141141
break;
142142
case LightStyles::WHITE_STRIPES:
143-
fx_white_stripes(pixels, currentColor);
143+
fx_white_stripes(ledsCount, currentColor);
144144
break;
145145
case LightStyles::WHITE_STRIPES_2:
146-
fx_white_stripes(pixels, currentColor, true);
146+
fx_white_stripes(ledsCount, currentColor, true);
147147
break;
148148
case LightStyles::KALEIDOSCOPE:
149-
fx_kaleidoscope(pixels, currentColor);
149+
fx_kaleidoscope(ledsCount, currentColor);
150150
break;
151151
case LightStyles::SOLID:
152152
default:
153-
fx_solid(pixels, currentColor, strobeFxTickMs > 0 ? 0 : 200);
153+
fx_solid(ledsCount, currentColor, strobeFxTickMs > 0 ? 0 : 200);
154154
break;
155155
}
156156

examples/color-light/color-light.h

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ namespace ColorLightApi {
5252
static const char LedsSpeed[] = "leds-spd";
5353
static const char LedsCount[] = "leds-cnt";
5454
static const char LedsPower[] = "leds-pwr";
55+
static const char LedsModules[] = "leds-mod";
5556
}
5657

5758
}
@@ -69,10 +70,13 @@ bool isConfigured = false;
6970
ColorLight* colorLight;
7071

7172
// LED strip
72-
uint16_t ledsCount = 0; int16_t ledsPin = -1;
73-
int16_t pixelsType, pixelsSpeed;
74-
Adafruit_NeoPixel* pixels = nullptr;
73+
uint16_t ledsCount = 0;
74+
int16_t ledsPin = -1;
7575
uint8_t maxPower = DEFAULT_MAX_POWER;
76+
// WS2810B RGB LED
77+
int16_t pixelsType;
78+
int16_t pixelsSpeed;
79+
Adafruit_NeoPixel* pixels = nullptr;
7680

7781
// Preset colors (normalized HSV)
7882
const int presetColorsCount = 7;
@@ -129,6 +133,8 @@ unsigned int strobeFxIntervalMs = 80; // limit strobe to 10Hz (20 + 80 -> 100m
129133
bool strobeOff = true;
130134
uint8_t currentStyleIndex = 0;
131135

136+
LinkedList<ColorLight*> colorLightList;
137+
132138
void refresh() {
133139
if (statusLed.isEnabled()) {
134140
statusLed.getLed()->show();
@@ -139,20 +145,25 @@ void refresh() {
139145
}
140146

141147
void renderPixels() {
148+
float pwr = ((float)maxPower / 100.0f);
142149
if (pixels != nullptr) {
143-
float pwr = ((float)maxPower / 100.0f);
144150
for (int i = 0; i < ledsCount; i++) {
145-
pixels->setPixelColor(i,
146-
static_cast<int>(round(animatedColors[i]->getRed() * pwr)),
147-
static_cast<int>(round(animatedColors[i]->getGreen() * pwr)),
148-
static_cast<int>(round(animatedColors[i]->getBlue() * pwr)));
151+
if (animatedColors[i]->getColor(pwr) != pixels->getPixelColor(i) && (!colorLightList.exist(i) || !colorLightList.get(i)->isOn())) {
152+
pixels->setPixelColor(i,
153+
static_cast<int>(round(animatedColors[i]->getRed() * pwr)),
154+
static_cast<int>(round(animatedColors[i]->getGreen() * pwr)),
155+
static_cast<int>(round(animatedColors[i]->getBlue() * pwr)));
156+
}
149157
}
150158
}
151159
if (statusLed.isEnabled()) {
152-
statusLed.getLed()->setPixelColor(0,
153-
static_cast<int>(round(animatedColors[0]->getRed())),
154-
static_cast<int>(round(animatedColors[0]->getGreen())),
155-
static_cast<int>(round(animatedColors[0]->getBlue())));
160+
auto c = animatedColors[0];
161+
if (c->getColor() != statusLed.getLed()->getPixelColor(0)) {
162+
statusLed.getLed()->setPixelColor(0,
163+
static_cast<int>(round(c->getRed())),
164+
static_cast<int>(round(c->getGreen())),
165+
static_cast<int>(round(c->getBlue())));
166+
}
156167
}
157168
}
158169

@@ -166,8 +177,24 @@ void createPixels()
166177
for (int i = 0; i < ledsCount; i++) {
167178
pixels->setPixelColor(i, 0, 0, 0);
168179
}
169-
//*/
170-
pixels->begin();
180+
181+
if (Config::getSetting(Configuration::LedsModules, "false").equals("true")) {
182+
for (int i = 0; i < ledsCount; i++) {
183+
auto address = String("L") + String(i + 1);
184+
auto name = String("LED ") + String(i + 1);
185+
colorLightList.add(new ColorLight(IO::IOEventDomains::HomeAutomation_HomeGenie, address.c_str(), name.c_str()));
186+
colorLightList[i]->onSetColor([i](LightColor color) {
187+
float pwr = ((float)maxPower / 100.0f);
188+
auto r = color.getRed() * pwr;
189+
auto g = color.getGreen() * pwr;
190+
auto b = color.getBlue() * pwr;
191+
pixels->setPixelColor(i, r, g, b);
192+
refresh();
193+
});
194+
homeGenie->addAPIHandler(colorLightList[i]);
195+
}
196+
}
197+
171198
}
172199
}
173200
void disposePixels() {

examples/smart-motor/smart-motor.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ void setup() {
7070

7171
is4wdRcCar = Config::getSetting("rcrcar-4wd").equals("true");
7272
if (is4wdRcCar) {
73+
Config::system.friendlyName = "Smart Car";
7374

7475
// Add *Motion* and *Steering* control modules if this device is for the
7576
// FPV 4WD RC Car https://homegenie.it/mini/1.2/examples/fpv-rc-car/
@@ -169,6 +170,9 @@ void setup() {
169170

170171
isRoboticArm = Config::getSetting("robotc-arm").equals("true");
171172
if (isRoboticArm) {
173+
if (!is4wdRcCar) {
174+
Config::system.friendlyName = "Robotic Arm";
175+
}
172176
// If this device is for the Robotic Arm only it will be using modules "S1" to "S4".
173177
// If this device is for RC-CAR with Robotic Arm, arm modules will be "S5" to "S8".
174178
// Configure Robotic Arm initial position to 0.5

platformio.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ data_dir = ./data/web
1414

1515
[env]
1616
# Official PlatformIO espressif32 and Arduino 2.x
17-
platform = espressif32@6.11.0
17+
platform = espressif32@6.12.0
1818
#
1919
# Official PlatformIO espressif32 and Arduino 3.x
2020
# but only supports ESP32, ESP32-S2, ESP32-C3 and ESP32-S3

src/service/api/CommonApi.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,6 @@ namespace Service { namespace API {
9393
static const char Scheduling_ModuleEvents[] = "Widget.Implements.Scheduling.ModuleEvents";
9494
}
9595
namespace Preference {
96-
// color-light
97-
static const char AudioLight[] = "Widget.Preference.AudioLight";
9896
// smart-motor - FPV RC Car controls
9997
static const char HomeLevel[] = "Widget.Preference.HomeLevel";
10098
static const char AutoHome[] = "Widget.Preference.AutoHome";

src/service/api/devices/ColorLight.cpp

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ namespace Service { namespace API { namespace devices {
3131
module->type = ModuleApi::ModuleType::Color;
3232

3333
// add properties
34-
module->setProperty(IOEventPaths::Status_ColorHsb, "0,0,1,.4");
34+
module->setProperty(IOEventPaths::Status_ColorHsb, "0,0,0");
3535

3636
onSetLevel([this](float l) {
37-
color.setColor(color.getHue(), color.getSaturation(), l, getDefaultTransition());
37+
color.setColor(color.getTargetHue(), color.getTargetSaturation(), l, getDefaultTransition());
3838
});
3939
}
4040

@@ -84,30 +84,24 @@ namespace Service { namespace API { namespace devices {
8484

8585
color.setColor(h, s, v, transition >= 0 ? transition : getDefaultTransition());
8686

87+
int size = snprintf(nullptr, 0, "%f,%f,%f", h, s, v);
88+
char eventValue[size + 1];
89+
sprintf(eventValue, "%f,%f,%f", h, s, v);
90+
module->setProperty(IOEventPaths::Status_ColorHsb, eventValue);
91+
8792
// Event Stream Message Enqueue (for MQTT/SSE/WebSocket propagation)
8893
auto eventsDisable = module->getProperty(IOEventPaths::Events_Disabled);
8994
if (eventsDisable == nullptr || eventsDisable->value == nullptr || eventsDisable->value != "1") {
9095
// color
91-
int size = snprintf(nullptr, 0, "%f,%f,%f", h, s, v);
92-
char eventValue[size + 1];
93-
sprintf(eventValue, "%f,%f,%f", h, s, v);
94-
auto msg = std::make_shared<QueuedMessage>(module, IOEventPaths::Status_ColorHsb, String(eventValue).c_str());
95-
module->setProperty(IOEventPaths::Status_ColorHsb, eventValue);
96-
HomeGenie::getInstance()->getEventRouter().signalEvent(msg);
97-
// level
98-
size = snprintf(nullptr, 0, "%f", v);
99-
char levelValue[size + 1];
100-
sprintf(levelValue, "%f", v);
101-
auto msg2 = std::make_shared<QueuedMessage>(module, IOEventPaths::Status_Level, String(levelValue).c_str());
102-
module->setProperty(IOEventPaths::Status_Level, levelValue);
103-
HomeGenie::getInstance()->getEventRouter().signalEvent(msg2);
96+
auto msgColor = std::make_shared<QueuedMessage>(module, IOEventPaths::Status_ColorHsb, String(eventValue).c_str());
97+
HomeGenie::getInstance()->getEventRouter().signalEvent(msgColor);
10498
}
10599

106-
if (v > 0) {
107-
Switch::status = SWITCH_STATUS_ON;
108-
Dimmer::onLevel = Switch::onLevel = v;
100+
if (v == 0.0f) {
101+
setStatus(SWITCH_STATUS_OFF);
109102
} else {
110-
Switch::status = SWITCH_STATUS_OFF;
103+
onLevel = v;
104+
setStatus(SWITCH_STATUS_ON);
111105
}
112106

113107
}

src/service/api/devices/ColorLight.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,21 @@ namespace Service { namespace API { namespace devices {
9494
float b = (float)orgb.b + ((float)(crgb.b - orgb.b) * getProgress());
9595
return b;
9696
}
97+
float getTargetHue() const {
98+
return h;
99+
}
100+
float getTargetSaturation() const {
101+
return s;
102+
}
103+
float getTargetValue() const {
104+
return v;
105+
}
106+
uint32_t getColor(float power = 1.0f) const {
107+
uint8_t r = static_cast<int>(round(getRed() * power));
108+
uint8_t g = static_cast<int>(round(getGreen() * power));
109+
uint8_t b = static_cast<int>(round(getBlue() * power));
110+
return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
111+
}
97112
private:
98113
float h = 0, s = 0, v = 0;
99114
float oh = 0, os = 0, ov = 0;

0 commit comments

Comments
 (0)