Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1163 lines
31 KiB

/*
LIGHT (EXPERIMENTAL) IR
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2017 by François Déchery
------------------------------------------------------------------------------------------
Features :
- ONLY RGB strips are supported (No RGBW or RGBWW)
- IR remote supported (but not mandatory)
- HSV (intuitive) WEB controls
- MQTT & API "color_rgb" + "color_hsv" + "brightness" parameters
- Uses the (amazing) Fastled library for fast and natural Color & Brightness
- Several Animation Modes and Speed (controlled from Remote + Web + MQTT + API)
------------------------------------------------------------------------------------------
Not currently Implemented :
- Saving/Restoring Settings
- HomeAssistant
------------------------------------------------------------------------------------------
*/
#ifdef LIGHT_PROVIDER_EXPERIMENTAL_RGB_ONLY_HSV_IR
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <FastLED.h>
// #### Defined ##########################################################################
#define ANIM_SPEED_STEP 20
#define ANIM1_SPEED 350 // flash ON Variable
#define ANIM1_PAUSE 200 // flash OFF fixed
#define ANIM2_SPEED 550 // strobe OFF variable
#define ANIM2_PAUSE 150 // storbe ON fixed
#define ANIM3_SPEED 100 // fade speed
#define ANIM4_SPEED 700 // smooth speed
#define ANIM5_SPEED 200 // party speed
#define BUTTONS_COUNT 24
#define LED_DURATION 70 // Status led ON duration
// #### Variables ########################################################################
unsigned long r_but_codes[]={ // IR remote buttons codes
IR_BUTTON_0 , // Brightness +
IR_BUTTON_1 , // Brightness -
IR_BUTTON_2 , // OFF
IR_BUTTON_3 , // ON
IR_BUTTON_4 , // Red
IR_BUTTON_5 , // Green
IR_BUTTON_6 , // Blue
IR_BUTTON_7 , // White
IR_BUTTON_8 , // R1
IR_BUTTON_9 , // G1
IR_BUTTON_10 , // B1
IR_BUTTON_11 , // Flash
IR_BUTTON_12 , // R2
IR_BUTTON_13 , // G2
IR_BUTTON_14 , // B2
IR_BUTTON_15 , // Strobe
IR_BUTTON_16 , // R3
IR_BUTTON_17 , // G3
IR_BUTTON_18 , // B3
IR_BUTTON_19 , // Fade
IR_BUTTON_20 , // R4
IR_BUTTON_21 , // G4
IR_BUTTON_22 , // B4
IR_BUTTON_23 // Smooth
};
unsigned long r_but_colors[]={ // IR remote buttons colors
0, // Brightness +
0, // Brightness -
0, // OFF
0, // ON
0xFF0000, // Red
0x00FF00, // Green
0x0000FF, // Blue
0xFFFFFF, // White
0xD13A01, // R1
0x00E644, // G1
0x0040A7, // B1
0, // Flash
0xE96F2A, // R2
0x00BEBF, // G2
0x56406F, // B2
0, // Strobe
0xEE9819, // R3
0x00799A, // G3
0x944E80, // B3
0, // Fade
0xFFFF00, // R4
0x0060A1, // G4
0xEF45AD, // B4
0 // Smooth
};
// variables declarations ###############################################################
CHSV _cur_color = CHSV(0,255,255);
CHSV _cur_anim_color = CHSV(0,0,0);
byte _cur_status = 0 ;
byte _cur_anim_mode = 0 ;
byte _cur_anim_step = 0;
boolean _cur_anim_dir = true;
unsigned long _cur_anim_speed = 1000;
unsigned long _anim_last_update = millis();
unsigned long _last_ir_button = 0;
unsigned long _last_status_led_time = 0;
IRrecv _ir_recv(LIGHT_IR_PIN); //IRrecv _ir_recv(IR_PIN, IR_LED_PIN); dont work. Why ?
decode_results _ir_results;
// #######################################################################################
// #### PRIVATE ##########################################################################
// #######################################################################################
// ---------------------------------------------------------------------------------------
void _updateStatusLed(){
if(millis() > _last_status_led_time + LED_DURATION ){
digitalWrite(LED1_PIN, LOW);
}
}
// ---------------------------------------------------------------------------------------
void _flashStatusLed(){
digitalWrite(LED1_PIN, HIGH);
_last_status_led_time=millis();
}
// ---------------------------------------------------------------------------------------
void _loopProcessIR() {
if (_ir_recv.decode(&_ir_results)) {
//dumpIR(&_ir_results);
//DEBUG_MSG_P(PSTR(".\n"));
unsigned long code = _ir_results.value;
DEBUG_MSG_P(PSTR("[IR] received : 0x%X "), code );
if( code == 0xFFFFFFFF){
code = _last_ir_button;
DEBUG_MSG_P(PSTR("(Repeat : %X) "), code );
}
DEBUG_MSG_P(PSTR("=> ") );
_processIrButtons(code);
_ir_recv.resume(); // Receive the next value
}
}
// ---------------------------------------------------------------------------------------
void _processIrButtons(unsigned long code) {
//DEBUG_MSG_P(PSTR("IR code : %X\n"), code );
boolean done=false;
for (int i = 0; i < BUTTONS_COUNT ; i = i + 1) {
if( code == r_but_codes[i] ){
//DEBUG_MSG_P(PSTR(" : %X -> "), r_but_colors[i] );
_last_ir_button = 0; //no repat else if specified
if(i == 0){
_buttonBrightness(true);
_last_ir_button = code;
delay(150); //debounce
}
else if(i == 1){
_buttonBrightness(false);
_last_ir_button = code;
delay(150); //debounce
}
else if(i == 2){
_buttonPower(false);
}
else if(i == 3){
_buttonPower(true);
}
else if(i == 11){
_buttonAnimMode(1);
}
else if(i == 15){
_buttonAnimMode(2);
}
else if(i == 19){
_buttonAnimMode(3);
}
else if(i == 23){
_buttonAnimMode(4);
}
else{
_buttonColorRVB(r_but_colors[i],0);
}
done=true;
lightUpdate(true, true);
}
}
if(!done){
_last_ir_button = 0;
//DEBUG_PRINTHEX(code);
DEBUG_MSG_P(PSTR("ignored!\n"));
}
}
// ---------------------------------------------------------------------------------------
void _buttonPower(boolean on){
_flashStatusLed();
DEBUG_MSG_P(PSTR("BUT Power: "));
_cur_anim_mode=0;
if(on){
_cur_status=1;
DEBUG_MSG_P(PSTR("ON : "));
_setLedsHSV(_cur_color);
}
else{
_cur_status=0;
DEBUG_MSG_P(PSTR("OFF : "));
_setLedsHSV(CHSV {0,0,0});
}
}
// ---------------------------------------------------------------------------------------
void _buttonAnimMode(byte val){
_flashStatusLed();
DEBUG_MSG_P(PSTR("BUT Anim Mode: %d\n"),val);
_processAnimation(val, true, true);
}
// ---------------------------------------------------------------------------------------
void _setAnimMode(byte val){
DEBUG_MSG_P(PSTR("[LIGHT] Set AnimMode: %d\n"),val);
_processAnimation(val, true, false);
}
// ---------------------------------------------------------------------------------------
void _buttonBrightness(boolean up){
DEBUG_MSG_P(PSTR("BUT Brightness: "));
if(up){
if(_cur_anim_mode==0){
DEBUG_MSG_P(PSTR("UP : "));
_buttonColorHSV(_cur_color, 1 );
}
else{
DEBUG_MSG_P(PSTR("FASTER\n"));
_buttonChangeSpeed( - ANIM_SPEED_STEP );
}
}
else{
if(_cur_anim_mode==0){
DEBUG_MSG_P(PSTR("DOWN : "));
_buttonColorHSV(_cur_color, -1 );
}
else{
DEBUG_MSG_P(PSTR("SLOWER\n"));
_buttonChangeSpeed( ANIM_SPEED_STEP );
}
}
}
// ---------------------------------------------------------------------------------------
void _buttonColorHSV(CHSV color, int offset){
_flashStatusLed();
DEBUG_MSG_P(PSTR("[LIGHT] Set Color to : "));
//DEBUG_MSG_P(PSTR("(from HSV=%d,%d,%d) "), color.h, color.s, color.v);
color=_dimHSV(color,offset);
//DEBUG_MSG_P(PSTR("(to HSV=%d,%d,%d) "), color.h, color.s, color.v);
_setLedsHSV(color);
if(color.v ==0 ){
_cur_status=0;
}
else{
_cur_status=1;
}
_cur_color=color;
_romSaveCurrentColor();
}
// ---------------------------------------------------------------------------------------
void _buttonColorRVB(CRGB color, int offset){
_buttonColorHSV(_rgbToHsv(color), offset);
}
// ---------------------------------------------------------------------------------------
void _buttonChangeSpeed(int offset){
_flashStatusLed();
if(offset !=0){
_cur_anim_speed=_cur_anim_speed + offset ;
}
}
// ---------------------------------------------------------------------------------------
CHSV _dimHSV(CHSV color, int offset){
offset=offset*10;
int bright=color.v + offset;
if(offset ==0){
return color;
}
else if(bright < 1){
bright=1; // no off
}
else if(bright > 255){
bright=255;
}
color.v=bright;
return color;
}
// ---------------------------------------------------------------------------------------
void _setBrightnessMapped(byte val){
DEBUG_MSG_P(PSTR("[LIGHT] Set from 0-100 Brightness : %u => "), val);
val =map(val,0,100,0,255);
_setBrightness(val);
}
// ---------------------------------------------------------------------------------------
void _setBrightness(byte val){
DEBUG_MSG_P(PSTR("[LIGHT] Set Brightness to : %u\n"), val);
_cur_color.v = val;
_cur_anim_color.v = val;
if(val==0){
_cur_status=0;
}
_buttonColorHSV(_cur_color,0);
}
// ---------------------------------------------------------------------------------------
void _setAnimSpeed(unsigned long speed){
if(speed !=0){
_cur_anim_speed=speed ;
}
}
// ---------------------------------------------------------------------------------------
void _setLedsRGB(CRGB rgb){
analogWrite(LIGHT_CH1_PIN, rgb.r);
analogWrite(LIGHT_CH2_PIN, rgb.g);
analogWrite(LIGHT_CH3_PIN, rgb.b);
if(_cur_anim_mode == 0){
DEBUG_MSG_P(PSTR("RGB=%3u,%3u,%3u\n"), rgb.r, rgb.g, rgb.b);
}
}
// ---------------------------------------------------------------------------------------
void _setLedsHSV(CHSV hsv){
if(_cur_anim_mode == 0){
DEBUG_MSG_P(PSTR("HSV=%3u,%3u,%3u - "), hsv.h, hsv.s, hsv.v);
}
_setLedsRGB( CHSV(hsv) );
}
// ---------------------------------------------------------------------------------------
void _confirmFlash(){
_setLedsRGB(CRGB::Black);
delay(70);
_setLedsRGB(CRGB::White);
delay(70);
_setLedsRGB(CRGB::Black);
delay(70);
_setLedsRGB(CRGB::White);
delay(70);
_setLedsRGB(CRGB::Black);
delay(70);
}
// ---------------------------------------------------------------------------------------
void _processAnimation(byte mode, boolean init, boolean is_button){
if(init){
if(_cur_anim_mode == mode && is_button){
_confirmFlash();
DEBUG_MSG_P(PSTR("[ANIM_%d] Stopped !!!\n"), mode);
_cur_anim_mode=0;
_cur_status=0;
return;
}
else if(mode == 0){
DEBUG_MSG_P(PSTR("[ANIM_%d] Stopped !!!\n"), mode);
_cur_anim_mode=0;
_cur_status=0;
return;
}
else{
if(is_button){
_confirmFlash();
}
DEBUG_MSG_P(PSTR("[ANIM_%d] Started !!!\n"), mode);
}
}
if(mode==1){
_anim1(init);
}
else if(mode==2){
_anim2(init);
}
else if(mode==3){
_anim3(init);
}
else if(mode==4){
_anim4(init);
}
else if(mode==5){
_anim5(init);
}
else{
//invalid mode
}
}
// ---------------------------------------------------------------------------------------
// anim1 : flash
void _anim1(boolean init){
if(init){
_cur_anim_mode = 1;
_cur_anim_speed = ANIM1_SPEED;
_cur_status = 1;
_cur_anim_step = 1;
}
unsigned long now= millis();
if(_cur_anim_step==1 && now > (_anim_last_update + _cur_anim_speed) ){
//DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
_setLedsHSV(_cur_color);
_cur_anim_step=0;
_anim_last_update = now;
}
else if(_cur_anim_step==0 && now > (_anim_last_update + ANIM1_PAUSE) ){
//DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
_setLedsHSV(CHSV {0,0,0});
_cur_anim_step=1;
_anim_last_update = now;
}
}
// ---------------------------------------------------------------------------------------
// anim2 : strobe
void _anim2(boolean init){
if(init){
_cur_anim_mode = 2;
_cur_anim_speed = ANIM2_SPEED;
_cur_status = 1;
_cur_anim_step = 1;
}
unsigned long now= millis();
if(_cur_anim_step==1 && now > (_anim_last_update + ANIM2_PAUSE) ){
//DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
_setLedsHSV(_cur_color);
_cur_anim_step=0;
_anim_last_update = now;
}
else if(_cur_anim_step==0 && now > (_anim_last_update + _cur_anim_speed) ){
//DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
_setLedsHSV(CHSV {0,0,0});
_cur_anim_step=1;
_anim_last_update = now;
}
}
// ---------------------------------------------------------------------------------------
// anim3 : fade
void _anim3(boolean init){
if(init){
_cur_anim_mode = 3;
_cur_anim_speed = ANIM3_SPEED;
_cur_status = 1;
_cur_anim_step = _cur_color.v;
}
unsigned long now= millis();
if( now > (_anim_last_update + _cur_anim_speed) ){
//DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
_setLedsHSV( CHSV(_cur_color.h, _cur_color.s, dim8_lin(_cur_anim_step)) );
if(_cur_anim_dir){
if(_cur_anim_step == 255){
_cur_anim_dir=false;
}
else{
_cur_anim_step++;
}
}
else{
if(_cur_anim_step == 1){
_cur_anim_dir=true;
}
else{
_cur_anim_step--;
}
}
_anim_last_update = now;
}
}
// ---------------------------------------------------------------------------------------
// anim4 : smooth
void _anim4(boolean init){
if(init){
_cur_anim_mode = 4;
_cur_anim_speed = ANIM4_SPEED;
_cur_status = 1;
_cur_anim_step = 0;
_cur_anim_color = _cur_color;
_cur_anim_color.v = 255;
}
unsigned long now= millis();
if( now > (_anim_last_update + _cur_anim_speed) ){
//DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
_cur_anim_color.h=_cur_anim_step;
_cur_anim_color.s=255;
_setLedsHSV( CHSV(_cur_anim_step,255,255) );
_cur_anim_step++;
_anim_last_update = now;
if(_cur_anim_step > 255){
_cur_anim_step=0;
}
}
}
// ---------------------------------------------------------------------------------------
// anim5 : party
void _anim5(boolean init){
if(init){
_cur_anim_mode = 5;
_cur_anim_speed = ANIM5_SPEED;
_cur_status = 1;
_cur_anim_step = 0;
_cur_anim_color = _cur_color;
_cur_anim_color.s= 255;
_cur_anim_color.v= 255;
}
unsigned long now= millis();
if(_cur_anim_step == 1 && now > (_anim_last_update + _cur_anim_speed) ){
DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
_cur_anim_color.h = random(0,255);
_setLedsHSV(_cur_anim_color);
_cur_anim_step = 0;
_anim_last_update = now;
}
else if(_cur_anim_step==0 && now > (_anim_last_update + _cur_anim_speed + 15) ){
//DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
_setLedsHSV(CHSV {0,0,0});
_cur_anim_step = 1;
_anim_last_update = now;
}
}
// ---------------------------------------------------------------------------------------
void _loopUpdateAnimation(){
_processAnimation(_cur_anim_mode, false, false);
}
// ---------------------------------------------------------------------------------------
CHSV _rgbToHsv(CRGB rgb){
/*
if(rgb.r <=1 && rgb.g <=1 && rgb.b <=1){
DEBUG_MSG_P(PSTR(" {Rounding RGB to black} "));
return CHSV {0,0,0};
}
*/
return rgb2hsv_approximate(rgb);
}
// ---------------------------------------------------------------------------------------
void _romSaveCurrentColor(){
//save it to 1,2,3 positions
//but dont stress eeprom if not needed
/*
CHSV rom =_romLoadColor();
if(_cur_color.h != rom.h){gw.saveState(1,_cur_color.h);}
if(_cur_color.s != rom.s){gw.saveState(2,_cur_color.s);}
if(_cur_color.v != rom.v){gw.saveState(3,_cur_color.v);}
*/
}
// ---------------------------------------------------------------------------------------
CHSV _romLoadColor(){
//load from 1,2,3 positions
CHSV color;
/*
color.h=gw.loadState(1);
color.s=gw.loadState(2);
color.v=gw.loadState(3);
*/
return color;
}
// ----------------------------------------------
CRGB _longToRgb(unsigned long rgb){
CRGB out;
out.r = rgb >> 16;
out.g = rgb >> 8 & 0xFF;
out.b = rgb & 0xFF;
return out;
}
// ---------------------------------------------------------------------------------------
CHSV _longToHsv(unsigned long hsv){
CHSV out;
out.h = hsv >> 16;
out.s = hsv >> 8 & 0xFF;
out.v = hsv & 0xFF;
return out;
}
// ---------------------------------------------------------------------------------------
unsigned long _rgbToLong(CRGB in){
return (((long)in.r & 0xFF) << 16) + (((long)in.g & 0xFF) << 8) + ((long)in.b & 0xFF);
}
// ---------------------------------------------------------------------------------------
unsigned long _hsvToLong(CHSV in){
return (((long)in.h & 0xFF) << 16) + (((long)in.s & 0xFF) << 8) + ((long)in.v & 0xFF);
}
// ---------------------------------------------------------------------------------------
CRGB _charToRgb(const char * rgb) {
char * p = (char *) rgb;
// if color begins with a # then assume HEX RGB
if (p[0] == '#') {
++p;
}
return _longToRgb( strtoul(p, NULL, 16) );
}
// ---------------------------------------------------------------------------------------
CHSV _charToHsv(const char * rgb) {
char * p = (char *) rgb;
// if color begins with a # then assume HEX RGB
if (p[0] == '#') {
++p;
}
return _longToHsv( strtoul(p, NULL, 16) );
}
// ---------------------------------------------------------------------------------------
boolean _charColorIsValid(const char * rgb){
char * p = (char *) rgb;
if (strlen(p) == 6 || strlen(p) == 7 ){
return true;
}
return false;
}
// ---------------------------------------------------------------------------------------
void _CurrentColorToRGB(char * buffer) {
snprintf_P(buffer, 8, PSTR("%06X"), _rgbToLong( CHSV(_cur_color)));
}
// ---------------------------------------------------------------------------------------
void _CurrentColorToHSV(char * buffer) {
snprintf_P(buffer, 8, PSTR("%06X"), _hsvToLong( _cur_color));
}
// ---------------------------------------------------------------------------------------
void _lightColorRestore() {
/*
for (unsigned int i=0; i < _channels.size(); i++) {
_channels[i].value = getSetting("ch", i, 0).toInt();
}
_brightness = getSetting("brightness", LIGHT_MAX_BRIGHTNESS).toInt();
lightUpdate(false, false);
*/
}
// ---------------------------------------------------------------------------------------
void _lightAPISetup() {
#if WEB_SUPPORT
// API entry points (protected with apikey)
if (lightHasColor()) {
apiRegister(MQTT_TOPIC_COLOR_RGB, MQTT_TOPIC_COLOR_RGB,
[](char * buffer, size_t len) {
_CurrentColorToRGB(buffer);
},
[](const char * payload) {
_SetLightColorRGB(payload);
lightUpdate(true, true);
}
);
apiRegister(MQTT_TOPIC_COLOR_HSV, MQTT_TOPIC_COLOR_HSV,
[](char * buffer, size_t len) {
_CurrentColorToHSV(buffer);
},
[](const char * payload) {
_SetLightColorHSV(payload);
lightUpdate(true, true);
}
);
apiRegister(MQTT_TOPIC_BRIGHTNESS, MQTT_TOPIC_BRIGHTNESS,
[](char * buffer, size_t len) {
snprintf_P(buffer, len, PSTR("%d"), _cur_color.v);
},
[](const char * payload) {
_setBrightness(atoi(payload));
lightUpdate(true, true);
}
);
apiRegister(MQTT_TOPIC_ANIM_MODE, MQTT_TOPIC_ANIM_MODE,
[](char * buffer, size_t len) {
snprintf_P(buffer, len, PSTR("%d"), _cur_anim_mode);
},
[](const char * payload) {
_setAnimMode(atoi(payload));
lightUpdate(true, true);
}
);
apiRegister(MQTT_TOPIC_ANIM_SPEED, MQTT_TOPIC_ANIM_SPEED,
[](char * buffer, size_t len) {
snprintf_P(buffer, len, PSTR("%d"), _cur_anim_speed);
},
[](const char * payload) {
_setAnimSpeed(atoi(payload));
lightUpdate(true, true);
}
);
}
/*
for (unsigned int id=0; id<lightChannels(); id++) {
char url[15];
snprintf_P(url, sizeof(url), PSTR("%s/%d"), MQTT_TOPIC_CHANNEL, id);
char key[10];
snprintf_P(key, sizeof(key), PSTR("%s%d"), MQTT_TOPIC_CHANNEL, id);
apiRegister(url, key,
[id](char * buffer, size_t len) {
snprintf_P(buffer, len, PSTR("%d"), lightChannel(id));
},
[id](const char * payload) {
lightChannel(id, atoi(payload));
lightUpdate(true, true);
}
);
}
*/
#endif // WEB_SUPPORT
}
/*
// #######################################################################################
// ---------------------------------------------------------------------------------------
CRGB _hsvToRgb(CHSV hsv){
if(hsv.v <=1){
DEBUG_MSG_P(PSTR(" {Rounding HSV to black}\n"));
hsv.v=0;
}
CRGB rgb=CHSV(hsv);
//round to black
if(rgb.r <=1 && rgb.g <=1 && rgb.b <=1){
DEBUG_MSG_P(PSTR(" {Rounding RGB to black}\n"));
rgb=CRGB::Black;
}
return rgb;
}
// ---------------------------------------------------------------------------------------
void _strToUpper(char * str){
for(int i=0; i<6; i++){
//a-z
if (97<=str[i]&&str[i]<=122){
str[i]-=32;
}
}
}
*/
// #######################################################################################
// #### PUBLIC ###########################################################################
// #######################################################################################
// ################################################################
void lightSetup() {
DEBUG_MSG_P(PSTR("[LIGHT] LIGHT_PROVIDER = %d (With IR)\n"), LIGHT_PROVIDER);
pinMode(LIGHT_CH1_PIN, OUTPUT);
pinMode(LIGHT_CH2_PIN, OUTPUT);
pinMode(LIGHT_CH3_PIN, OUTPUT);
_ir_recv.enableIRIn(); // Start the receiver
//confirmRgb();
_cur_color = _romLoadColor();
_lightColorRestore();
_lightAPISetup();
mqttRegister(_lightMQTTCallback);
}
// ---------------------------------------------------------------------------------------
void lightLoop() {
_loopProcessIR();
_loopUpdateAnimation();
_updateStatusLed();
}
// ---------------------------------------------------------------------------------------
void lightUpdate(bool save, bool forward) {
//DEBUG_MSG_P(PSTR("[LIGHT] Updating... \n"));
// _lightProviderUpdate();
// Report color & brightness to MQTT broker
if (forward) lightMQTT();
// Report color to WS clients (using current brightness setting)
#if WEB_SUPPORT
{
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["colorVisible"] = 1;
root["useColor"] = getSetting("useColor", LIGHT_USE_COLOR).toInt() == 1;
root["useWhite"] = getSetting("useWhite", LIGHT_USE_WHITE).toInt() == 1;
root["useGamma"] = getSetting("useGamma", LIGHT_USE_GAMMA).toInt() == 1;
root["anim_mode"] = lightAnimMode();
root["anim_speed"] = lightAnimSpeed();
JsonObject& color_hsv = root.createNestedObject("color_hsv");
color_hsv["h"] = lightColorH();
color_hsv["s"] = lightColorS();
color_hsv["v"] = lightColorV();
//root["color_hsv"] = lightColor();
//root["brightness"] = _cur_color.v;
// RGB channels
//JsonArray& channels = root.createNestedArray("channels");
//for (unsigned char id=0; id < lightChannels(); id++) {
// channels.add(lightChannel(id));
//}
// Relay
JsonArray& relay = root.createNestedArray("relayStatus");
relay.add(_cur_status);
String output;
root.printTo(output);
wsSend(output.c_str());
//DEBUG_MSG_P(PSTR("JSON : %s"), output.c_str() );
}
#endif
// Delay saving to EEPROM 5 seconds to avoid wearing it out unnecessarily
//if (save) colorTicker.once(LIGHT_SAVE_DELAY, _lightColorSave);
}
// ---------------------------------------------------------------------------------------
void lightMQTT() {
char buffer[8];
if (lightHasColor()) {
// RGB Color
_CurrentColorToRGB(buffer);
mqttSend(MQTT_TOPIC_COLOR_RGB, buffer);
// HSV Color
_CurrentColorToHSV(buffer);
mqttSend(MQTT_TOPIC_COLOR_HSV, buffer);
// Brightness
snprintf_P(buffer, sizeof(buffer), PSTR("%d"), _cur_color.v);
mqttSend(MQTT_TOPIC_BRIGHTNESS, buffer);
// Anim Mode
snprintf_P(buffer, sizeof(buffer), PSTR("%d"), _cur_anim_mode);
mqttSend(MQTT_TOPIC_ANIM_MODE, buffer);
// Anim Speed
snprintf_P(buffer, sizeof(buffer), PSTR("%d"), _cur_anim_speed);
mqttSend(MQTT_TOPIC_ANIM_SPEED, buffer);
}
// Channels
//for (unsigned int i=0; i < _channels.size(); i++) {
// snprintf_P(buffer, sizeof(buffer), PSTR("%d"), _channels[i].value);
// mqttSend(MQTT_TOPIC_CHANNEL, i, buffer);
//}
}
// ---------------------------------------------------------------------------------------
// Get Number of Channels
unsigned char lightChannels() {
return 3;
}
// ---------------------------------------------------------------------------------------
// Get Channel's Value
unsigned int lightChannel(unsigned char id) {
CRGB current_rvb = CHSV(_cur_color);
if(id == 0 ){
return current_rvb.r;
}
else if(id == 1 ){
return current_rvb.g;
}
else if(id == 2 ){
return current_rvb.b;
}
else{
DEBUG_MSG_P(PSTR(" [ERROR] GET lightChannel : %s\n"), id);
return 0;
}
}
// ---------------------------------------------------------------------------------------
// Set Channel's Value
void lightChannel(unsigned char id, unsigned int value) {
DEBUG_MSG_P(PSTR("[WEB|API] Set Color Channel "));
value= constrain(value, 0, 255);
CRGB current_rvb = CHSV(_cur_color);
if(id == 0 ){
DEBUG_MSG_P(PSTR("RED to : %d => "), value);
current_rvb.r=value;
_buttonColorRVB(current_rvb,0);
}
else if(id == 1 ){
DEBUG_MSG_P(PSTR("GREEN to : %d => "), value);
current_rvb.g=value;
_buttonColorRVB(current_rvb,0);
}
else if(id == 2 ){
DEBUG_MSG_P(PSTR("BLUE to : %d => "), value);
current_rvb.b=value;
_buttonColorRVB(current_rvb,0);
}
else{
DEBUG_MSG_P(PSTR(" [ERROR] SET lightChannel %s To %d \n"), id, value);
}
}
// ---------------------------------------------------------------------------------------
// Get Brightness
unsigned int lightBrightness() {
return _cur_color.v;
}
// ---------------------------------------------------------------------------------------
// Set Brightness
void lightBrightness(unsigned int b) {
b=constrain(b, 0, 255);
DEBUG_MSG_P(PSTR("[WEB|API] Set Brightness to : %d\n"), b);
_cur_color.v=b;
_setLedsHSV(_cur_color);
//set status
if(b > 0){
_cur_status=1;
}
else{
_cur_status=0;
}
}
// ---------------------------------------------------------------------------------------
// Get Color
String lightColor() {
char rgb[8];
snprintf_P(rgb, 8, PSTR("#%06X"), _rgbToLong( CHSV(_cur_color)));
return String(rgb);
//return String("");
}
String lightColorH(){
return String(_cur_color.h);
}
String lightColorS(){
return String(_cur_color.s);
}
String lightColorV(){
return String(_cur_color.v);
}
// ---------------------------------------------------------------------------------------
// Set Color
void lightColor(const char * color) {
//used only from settings
_SetLightColorRGB(color);
}
void _SetLightColorRGB(const char * color) {
//used only from settings
DEBUG_MSG_P(PSTR("[WEB|API] Set (#RGB) Color to : "));
if( _charColorIsValid(color) ){
DEBUG_MSG_P(PSTR("%s \n"), color);
_buttonColorRVB(_charToRgb(color), 0);
}
else{
DEBUG_MSG_P(PSTR(" Canceled ('%s' is invalid) !\n"), color);
}
}
void _SetLightColorHSV(const char * color) {
DEBUG_MSG_P(PSTR("[WEB|API] Set (#HSV) Color to : "));
if( _charColorIsValid(color) ){
DEBUG_MSG_P(PSTR("%s \n"), color);
_buttonColorHSV(_charToHsv(color), 0);
}
else{
DEBUG_MSG_P(PSTR(" Canceled ('%s' is invalid) !\n"), color);
}
}
void setLightColor (const char * h, const char * s, const char * v){
DEBUG_MSG_P(PSTR("[WEB|API] Set Color from (%s,%s,%s) "), h, s, v);
CHSV color;
color.h=strtoul(h, NULL, 10);
color.s=strtoul(s, NULL, 10);
color.v=strtoul(v, NULL, 10);
DEBUG_MSG_P(PSTR("to (%d,%d,%d) "), color.h, color.s, color.v);
_buttonColorRVB(color, 0);
}
// ---------------------------------------------------------------------------------------
bool lightHasColor() {
// bool useColor = getSetting("useColor", LIGHT_USE_COLOR).toInt() == 1;
// return useColor && (_channels.size() > 2);
//if(_cur_status || _cur_anim_mode){return 1;}
return true;
}
// ---------------------------------------------------------------------------------------
// Get State
bool lightState() {
//DEBUG_MSG_P(PSTR("[->LIGHT] _cur_status is : %d \n"),_cur_status);
return _cur_status;
}
// ---------------------------------------------------------------------------------------
// Set State
void lightState(bool state){
DEBUG_MSG_P(PSTR("[WEB|API] Set Relay to : %u => "), state);
//if(state != _cur_status){
_buttonPower(state);
//}
}
// ---------------------------------------------------------------------------------------
String lightAnimMode(){
return String(_cur_anim_mode);
}
void lightAnimMode(const char * val){
DEBUG_MSG_P(PSTR("[WEB|API] Set AnimMode to %s\n"), val);
_setAnimMode(strtoul(val, NULL, 10));
}
// ---------------------------------------------------------------------------------------
String lightAnimSpeed(){
return String(_cur_anim_speed);
}
void lightAnimSpeed(const char * val){
DEBUG_MSG_P(PSTR("[WEB|API] Set AnimSpeed to %s \n"), val);
_setAnimSpeed(strtoul(val, NULL, 10));
}
// ---------------------------------------------------------------------------------------
// MQTT
// ---------------------------------------------------------------------------------------
void _lightMQTTCallback(unsigned int type, const char * topic, const char * payload) {
if (type == MQTT_CONNECT_EVENT) {
if (lightHasColor()) {
mqttSubscribe(MQTT_TOPIC_BRIGHTNESS);
mqttSubscribe(MQTT_TOPIC_COLOR_RGB);
mqttSubscribe(MQTT_TOPIC_COLOR_HSV);
mqttSubscribe(MQTT_TOPIC_ANIM_MODE);
mqttSubscribe(MQTT_TOPIC_ANIM_SPEED);
}
//char buffer[strlen(MQTT_TOPIC_CHANNEL) + 3];
//snprintf_P(buffer, sizeof(buffer), PSTR("%s/+"), MQTT_TOPIC_CHANNEL);
//mqttSubscribe(buffer);
}
if (type == MQTT_MESSAGE_EVENT) {
// Match topic
String t = mqttSubtopic((char *) topic);
// Color RGB
if (t.equals(MQTT_TOPIC_COLOR_RGB)) {
_SetLightColorRGB(payload);
lightUpdate(true, mqttForward());
}
// Color HSV
if (t.equals(MQTT_TOPIC_COLOR_HSV)) {
_SetLightColorHSV(payload);
lightUpdate(true, mqttForward());
}
// ANIM Mode
if (t.equals(MQTT_TOPIC_ANIM_MODE)) {
_setAnimMode(atoi(payload));
lightUpdate(true, mqttForward());
}
// ANIM Speed
if (t.equals(MQTT_TOPIC_ANIM_SPEED)) {
_setAnimSpeed(atoi(payload));
lightUpdate(true, mqttForward());
}
// Brightness
if (t.equals(MQTT_TOPIC_BRIGHTNESS)) {
_setBrightness (constrain(atoi(payload), 0, LIGHT_MAX_BRIGHTNESS));
lightUpdate(true, mqttForward());
}
/*
// Channel
if (t.startsWith(MQTT_TOPIC_CHANNEL)) {
unsigned int channelID = t.substring(strlen(MQTT_TOPIC_CHANNEL)+1).toInt();
if (channelID >= _channels.size()) {
DEBUG_MSG_P(PSTR("[LIGHT] Wrong channelID (%d)\n"), channelID);
return;
}
lightChannel(channelID, atoi(payload));
lightUpdate(true, mqttForward());
}
*/
}
}
#endif // LIGHT_IR_PIN