Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add light palette support #8150

Merged
merged 1 commit into from
Apr 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tasmota/i18n.h
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@
#define D_CMND_LED "Led"
#define D_CMND_LEDTABLE "LedTable"
#define D_CMND_FADE "Fade"
#define D_CMND_PALETTE "Palette"
#define D_CMND_PIXELS "Pixels"
#define D_CMND_RGBWWTABLE "RGBWWTable"
#define D_CMND_ROTATION "Rotation"
Expand Down
1 change: 1 addition & 0 deletions tasmota/my_user_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@
#define USE_SM2135 // Add support for SM2135 RGBCW led control as used in Action LSC (+0k6 code)
#define USE_SONOFF_L1 // Add support for Sonoff L1 led control
#define USE_ELECTRIQ_MOODL // Add support for ElectriQ iQ-wifiMOODL RGBW LED controller (+0k3 code)
#define USE_LIGHT_PALETTE // Add support for color palette (+0k9 code)

// -- Counter input -------------------------------
#define USE_COUNTER // Enable inputs as counter (+0k8 code)
Expand Down
186 changes: 176 additions & 10 deletions tasmota/xdrv_04_light.ino
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,20 @@ const uint8_t LIGHT_COLOR_SIZE = 25; // Char array scolor size
const char kLightCommands[] PROGMEM = "|" // No prefix
D_CMND_COLOR "|" D_CMND_COLORTEMPERATURE "|" D_CMND_DIMMER "|" D_CMND_DIMMER_RANGE "|" D_CMND_LEDTABLE "|" D_CMND_FADE "|"
D_CMND_RGBWWTABLE "|" D_CMND_SCHEME "|" D_CMND_SPEED "|" D_CMND_WAKEUP "|" D_CMND_WAKEUPDURATION "|"
D_CMND_WHITE "|" D_CMND_CHANNEL "|" D_CMND_HSBCOLOR "|UNDOCA" ;
D_CMND_WHITE "|" D_CMND_CHANNEL "|" D_CMND_HSBCOLOR
#ifdef USE_LIGHT_PALETTE
"|" D_CMND_PALETTE
#endif // USE_LIGHT_PALETTE
"|UNDOCA" ;

void (* const LightCommand[])(void) PROGMEM = {
&CmndColor, &CmndColorTemperature, &CmndDimmer, &CmndDimmerRange, &CmndLedTable, &CmndFade,
&CmndRgbwwTable, &CmndScheme, &CmndSpeed, &CmndWakeup, &CmndWakeupDuration,
&CmndWhite, &CmndChannel, &CmndHsbColor, &CmndUndocA };
&CmndWhite, &CmndChannel, &CmndHsbColor,
#ifdef USE_LIGHT_PALETTE
&CmndPalette,
#endif // USE_LIGHT_PALETTE
&CmndUndocA };

// Light color mode, either RGB alone, or white-CT alone, or both only available if ct_rgb_linked is false
enum LightColorModes {
Expand Down Expand Up @@ -276,6 +284,10 @@ struct LIGHT {
#ifdef USE_DEVICE_GROUPS
bool devgrp_no_channels_out = false; // don't share channels with device group (e.g. if scheme set by other device)
#endif // USE_DEVICE_GROUPS
#ifdef USE_LIGHT_PALETTE
uint8_t palette_count = 0; // palette entry count
uint8_t * palette; // dynamically allocated palette color array
#endif // USE_LIGHT_PALETTE
uint16_t fade_start_10[LST_MAX] = {0,0,0,0,0};
uint16_t fade_cur_10[LST_MAX];
uint16_t fade_end_10[LST_MAX]; // 10 bits resolution target channel values
Expand Down Expand Up @@ -1625,13 +1637,45 @@ void LightPreparePower(power_t channels = 0xFFFFFFFF) { // 1 = only RGB, 2 =
LightState(0);
}

#ifdef USE_LIGHT_PALETTE
void LightSetPaletteEntry(void)
{
uint8_t bri = light_state.getBri();
uint8_t * palette_entry = &Light.palette[Light.wheel * LST_MAX];
for (int i = 0; i < LST_MAX; i++) {
Light.new_color[i] = changeUIntScale(palette_entry[i], 0, 255, 0, bri);
}
light_state.setChannelsRaw(Light.new_color);
if (!Light.pwm_multi_channels) {
light_state.setCW(Light.new_color[3], Light.new_color[4], true);
if (Light.new_color[0] || Light.new_color[1] || Light.new_color[2]) light_state.addRGBMode();
}
}
#endif // USE_LIGHT_PALETTE

void LightCycleColor(int8_t direction)
{
// if (Light.strip_timer_counter % (Settings.light_speed * 2)) { return; } // Speed 1: 24sec, 2: 48sec, 3: 72sec, etc
if (Settings.light_speed > 3) {
if (Light.strip_timer_counter % (Settings.light_speed - 2)) { return; } // Speed 4: 24sec, 5: 36sec, 6: 48sec, etc
}

#ifdef USE_LIGHT_PALETTE
if (Light.palette_count) {
if (0 == direction) {
Light.wheel = random(Light.palette_count);
}
else {
Light.wheel += direction;
if (Light.wheel >= Light.palette_count) {
Light.wheel = (direction < 0 ? Light.palette_count - 1 : 0);
}
}
LightSetPaletteEntry();
return;
}
#endif // USE_LIGHT_PALETTE

if (0 == direction) {
if (Light.random == Light.wheel) {
Light.random = random(255);
Expand Down Expand Up @@ -2187,7 +2231,13 @@ void LightHandleDevGroupItem(void)
break;
case DGR_ITEM_LIGHT_FIXED_COLOR:
if (Light.subtype >= LST_RGBW) {
#ifdef USE_LIGHT_PALETTE
value = value % (Light.palette_count ? Light.palette_count : MAX_FIXED_COLOR);
if (Light.palette_count || value) {
#else // USE_LIGHT_PALETTE
value = value % MAX_FIXED_COLOR;
if (value) {
#endif // !USE_LIGHT_PALETTE
bool save_decimal_text = Settings.flag.decimal_text;
char str[16];
LightColorEntry(str, sprintf_P(str, PSTR("%u"), value));
Expand Down Expand Up @@ -2323,19 +2373,55 @@ void CmndSupportColor(void)
{
bool valid_entry = false;
bool coldim = false;
#ifdef USE_LIGHT_PALETTE
uint8_t * color_ptr;
#endif // USE_LIGHT_PALETTE

if (XdrvMailbox.data_len > 0) {
valid_entry = LightColorEntry(XdrvMailbox.data, XdrvMailbox.data_len);
#ifdef USE_LIGHT_PALETTE
if (Light.palette_count) {
if (XdrvMailbox.data_len == 1 && ('+' == XdrvMailbox.data[0] || '-' == XdrvMailbox.data[0])) {
int8_t direction = ('+' == XdrvMailbox.data[0] ? 1 : -1);
Light.wheel += direction;
if (Light.wheel >= Light.palette_count) {
Light.wheel = (direction < 0 ? Light.palette_count - 1 : 0);
}
}
else {
Light.wheel = (atoi(XdrvMailbox.data) - 1);
}
color_ptr = &Light.palette[Light.wheel * LST_MAX];
valid_entry = true;
}
else {
color_ptr = Light.entry_color;
#endif // USE_LIGHT_PALETTE
valid_entry = LightColorEntry(XdrvMailbox.data, XdrvMailbox.data_len);
#ifdef USE_LIGHT_PALETTE
}
#endif // USE_LIGHT_PALETTE
if (valid_entry) {
if (XdrvMailbox.index <= 2) { // Color(1), 2
uint32_t old_bri = light_state.getBri();
// change all channels to specified values
light_controller.changeChannels(Light.entry_color);
if (2 == XdrvMailbox.index) {
// If Color2, set back old brightness
light_controller.changeBri(old_bri);
#ifdef USE_LIGHT_PALETTE
if (Light.palette_count && XdrvMailbox.index == 1) {
LightSetPaletteEntry();
}

else {
#endif // USE_LIGHT_PALETTE
uint32_t old_bri = light_state.getBri();
// change all channels to specified values
#ifdef USE_LIGHT_PALETTE
light_controller.changeChannels(color_ptr);
#else // USE_LIGHT_PALETTE
light_controller.changeChannels(Light.entry_color);
#endif // !USE_LIGHT_PALETTE
if (2 == XdrvMailbox.index) {
// If Color2, set back old brightness
light_controller.changeBri(old_bri);
}
#ifdef USE_LIGHT_PALETTE
}
#endif // USE_LIGHT_PALETTE
Settings.light_scheme = 0;
#ifdef USE_DEVICE_GROUPS
LightUpdateScheme();
Expand Down Expand Up @@ -2747,6 +2833,86 @@ void CmndWakeupDuration(void)
ResponseCmndNumber(Settings.light_wakeup);
}

#ifdef USE_LIGHT_PALETTE
void CmndPalette(void)
{
uint8_t * palette_entry;
char * color;
char * p;

// Palette Color[ ...]
if (XdrvMailbox.data_len) {
Light.wheel = 0;
if (Light.palette) {
free(Light.palette);
Light.palette = nullptr;
Light.palette_count = 0;
}
if (XdrvMailbox.data_len > 1 || XdrvMailbox.data[0] != '0') {
for (int pass = 0;; pass++) {
Light.palette_count = 0;
color = XdrvMailbox.data;
for (;;) {
p = strchr(color, ' ');
if (p) *p = 0;
color = Trim(color);
if (*color && LightColorEntry(color, strlen(color))) {
if (pass) {
memcpy(palette_entry, Light.entry_color, LST_MAX);
if (!Light.pwm_multi_channels && LST_COLDWARM == Light.subtype) {
palette_entry[3] = palette_entry[0];
palette_entry[4] = palette_entry[1];
}
palette_entry += LST_MAX;
}
Light.palette_count++;
}
if (!p) break;
*p = ' ';
color = p + 1;
}
if (pass) break;
if (!(Light.palette = (uint8_t *)malloc(Light.palette_count * LST_MAX))) return;
palette_entry = Light.palette;
}
}
}

char palette_str[5 * Light.subtype * Light.palette_count + 3];
const char * fmt;
p = palette_str;
*p++ = '[';
if (Light.palette_count) {
palette_entry = Light.palette;
if (Settings.flag.decimal_text) { // SetOption17 - Switch between decimal or hexadecimal output
for (int entry = 0; entry < Light.palette_count; entry++) {
*p++ = '"';
for (uint32_t i = 0; i < Light.subtype; i++) {
if (i > 0) *p++ = ',';
p += sprintf_P(p, PSTR("%d"), palette_entry[i]);
}
palette_entry += LST_MAX;
}
*p++ = '"';
*p++ = ',';
}
else {
for (int entry = 0; entry < Light.palette_count; entry++) {
for (uint32_t i = 0; i < Light.subtype; i++) {
p += sprintf_P(p, PSTR("%02X"), palette_entry[i]);
}
palette_entry += LST_MAX;
}
*p++ = ',';
}
p--;
}
*p++ = ']';
*p = 0;
ResponseCmndChar(palette_str);
}
#endif // USE_LIGHT_PALETTE

void CmndUndocA(void)
{
// Theos legacy status
Expand Down
16 changes: 4 additions & 12 deletions tasmota/xdrv_35_pwm_dimmer.ino
Original file line number Diff line number Diff line change
Expand Up @@ -400,18 +400,10 @@ void PWMDimmerHandleButton(void)
else
#endif // USE_PWM_DIMMER_REMOTE
uint8_value = Light.fixed_color_index;
if (is_down_button) {
if (uint8_value)
uint8_value--;
else
uint8_value = MAX_FIXED_COLOR;
}
else {
if (uint8_value < MAX_FIXED_COLOR)
uint8_value++;
else
uint8_value = 0;
}
if (is_down_button)
uint8_value--;
else
uint8_value++;
#ifdef USE_PWM_DIMMER_REMOTE
if (!active_device_is_local)
active_remote_pwm_dimmer->fixed_color_index = uint8_value;
Expand Down