diff --git a/src/main.cpp b/src/main.cpp index 0ca23de..8156791 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,14 @@ //Upload config: platformio run --target uploadfs +#define TISCHLICHT +//#define KUECHENLICHT + + +#ifdef TISCHLICHT + #define DUALCOLOR +#endif + #include #include @@ -15,7 +23,11 @@ bool enableHandler(const HomieRange& range, const String& value); bool fadetimeHandler(const HomieRange& range, const String& value); bool brightnessHandler(const HomieRange& range, const String& value); +#ifdef DUALCOLOR +bool temperatureHandler(const HomieRange& range, const String& value); +#endif void loopHandler(); +float mapFloat(float x, float in_min, float in_max, float out_min, float out_max); //#define DEBUG //turns on continuous serial debug printing @@ -23,19 +35,38 @@ void loopHandler(); HomieNode lightNode("light", "Light", "light"); //paramters: topic, $name, $type +#ifdef TISCHLICHT + #define LED_WW 14 //D5 = GPIO14 (pin5) + #define LED_CW 12 //D6 = GPIO12 (pin6) +#endif +#ifdef KUECHENLICHT + #define LED_PWM D5 +#endif -#define LED_PWM D5 +#ifdef TISCHLICHT + #define BTN_A 13 //D7 = GPIO13 (pin 7) + #define BTN_B 15 //D8 = GPIO15 (pin 10) +#endif +#ifdef KUECHENLICHT + #define BTN_A D7 +#endif -#define BTN_A D7 #define PWM_MAX 1023 //10 bit dac -#define PWM_FREQUENCY 1000 //default: 1000 Hz + +#ifdef TISCHLICHT + #define PWM_FREQUENCY 500 //default: 1000 Hz +#endif +#ifdef KUECHENLICHT + #define PWM_FREQUENCY 1000 //default: 1000 Hz +#endif + boolean enable=false; float enable_fadevalue=0; //0=off, 1=on float enable_fadevalue_change_per_loop=0.01; //fixed value. For manual calculatoin: enable_fadevalue_change_per_loop=_difference/fadetime*UPDATETIME; -float set_brightness=2; //0 to 1 +float set_brightness=2; //0 to 2. 1 is maximum brightness with full color range still possible. 2 is full brightness regardless of possible color temp #define BRIGHTNESS_MIN 0.0 #define BRIGHTNESS_MAX 2.0 //if temperature is in between both strips brightness of 2 means both are at full power. otherwise brightness will be clipped #define BRIGHTNESSCURVE 1.4 @@ -43,6 +74,17 @@ float brightness=set_brightness; float brightness_change_per_loop=0; //will be calculated by Handler +#ifdef TISCHLICHT + #define TEMPERATURE_MIN 2760 //temperature of warm white leds + #define TEMPERATURE_MAX 5640 //temperature of cold white leds +#endif + +#ifdef DUALCOLOR + float set_temperature=(TEMPERATURE_MAX+TEMPERATURE_MIN)/2; + float temperature=set_temperature; + float temperature_change_per_loop=0; //will be calculated by Handler +#endif + uint16_t fadetime=0; //0=instant. value is time in milliseconds #define FADETIME_MIN 0 #define FADETIME_MAX 60000 @@ -55,12 +97,21 @@ long last_updatetime=0; long last_buttonupdatetime=0; uint8_t btnAstate=0; //for button state machine long btnAtime=0; +#ifdef DUALCOLOR + uint8_t btnBstate=0; //for button state machine + long btnBtime=0; +#endif #define BTNHOLDTIME 1000 boolean holdDirection_brightness=false; +#ifdef DUALCOLOR + boolean holdDirection_temperature=false; +#endif #define HOLDBRIGHTNESSCHANGE_PER_LOOP 0.01 //depends on BUTTONUPDATETIME. BUTTONUPDATETIME/1000/HOLDBRIGHTNESSCHANGE_PER_LOOP=seconds to change a full cycle(0 to 1) - +#ifdef DUALCOLOR + #define HOLDTEMPERATURECHANGE_PER_LOOP 10.0 // (TEMPERATURE_MAX-TEMPERATURE_MIN)*BUTTONUPDATETIME/1000/HOLDBRIGHTNESSCHANGE_PER_LOOP=seconds to change a full cycle (min to max) +#endif boolean flag_updatePWM=false; //if manually set brightness or temperature, set this flag //Debug @@ -70,15 +121,35 @@ long last_debugupdatetime=0; //To check if values changed (for mqtt response) boolean known_enable=!enable; //start with differend known values, actual values will be send first float known_set_brightness=set_brightness+1; +#ifdef DUALCOLOR + float known_set_temperature=set_temperature+1; +#endif void setup() { Serial.begin(115200); Serial.println("Hello"); - pinMode(LED_PWM, OUTPUT); - analogWriteFreq(PWM_FREQUENCY); - analogWrite(LED_PWM, PWM_MAX); //high = off - pinMode(BTN_A, INPUT); + analogWriteFreq(PWM_FREQUENCY); + #ifdef TISCHLICHT + pinMode(LED_WW, OUTPUT); + pinMode(LED_CW, OUTPUT); + analogWrite(LED_CW, PWM_MAX); //high = off + analogWrite(LED_WW, PWM_MAX); //high = off + #endif + #ifdef KUECHENLICHT + pinMode(LED_PWM, OUTPUT); + analogWrite(LED_PWM, PWM_MAX); //high = off + #endif + + + #ifdef TISCHLICHT + pinMode(BTN_A, INPUT); + pinMode(BTN_B, INPUT); + #endif + #ifdef KUECHENLICHT + pinMode(BTN_A, INPUT); + #endif + Homie_setFirmware(FW_NAME, FW_VERSION); Homie_setBrand(FW_NAME); @@ -87,6 +158,9 @@ void setup() { lightNode.advertise("brightness").settable(brightnessHandler); lightNode.advertise("fadetime").settable(fadetimeHandler); lightNode.advertise("enable").settable(enableHandler); + #ifdef DUALCOLOR + lightNode.advertise("temperature").settable(temperatureHandler); + #endif Homie.setup(); @@ -138,10 +212,48 @@ void loopHandler() { } // #### END Button A Check #### + #ifdef DUALCOLOR + // #### Button B #### + boolean flag_btnBpress=false; //short press on release + boolean flag_btnBholdstart=false; //long press on start + boolean flag_btnBhold=false; //long press after long press time + boolean flag_btnBholdrelease=false; //long press on release + + if (digitalRead(BTN_B)) { //Button State Machine + switch (btnBstate) { + case 0: //was not pressed + btnBstate=1; + btnBtime=loopmillis; //start timer + break; + case 1: //was pressed last time checked + if (loopmillis>btnBtime+BTNHOLDTIME) { + btnBstate=2; + flag_btnBholdstart=true; + } + break; + case 2: //button hold time reached + flag_btnBhold=true; + break; + } + }else { + if (btnBstate==1) { //short press + btnBstate=0; //reset state + flag_btnBpress=true; + }else if(btnBstate==2) { //long press released + flag_btnBholdrelease=true; + btnBstate=0; //reset state + } + } + // #### END Button B Check #### + #endif //Button handling +#ifdef DUALCOLOR + if (flag_btnApress || flag_btnBpress){ //short press either button +#else if (flag_btnApress){ //short press button +#endif enable = !enable; //switch on/off flag_updatePWM=true; //update pwm values } @@ -179,6 +291,35 @@ void loopHandler() { } +#ifdef DUALCOLOR + // Button B Longpress Handling + if (flag_btnBholdstart) { + /* //Change only hold direction at extremes + if (set_temperature>=TEMPERATURE_MAX) { //if hold started with brightness at one extreme + holdDirection_temperature=false; //direction decrease + } + if (set_temperature<=TEMPERATURE_MIN) { //if hold started with brightness at one extreme + holdDirection_temperature=true; //direction increase + } + */ + holdDirection_temperature=!holdDirection_temperature; //change direction everytime + } + if (flag_btnBhold) { //brightness + if (holdDirection_temperature) { + set_temperature += HOLDTEMPERATURECHANGE_PER_LOOP; + }else{ + set_temperature -= HOLDTEMPERATURECHANGE_PER_LOOP; + } + set_temperature = constrain(set_temperature, TEMPERATURE_MIN, TEMPERATURE_MAX); + + temperature=set_temperature; //change immediately + flag_updatePWM=true; //update pwm values + } + if (flag_btnBholdrelease) { + + } +#endif + } } @@ -196,6 +337,16 @@ void loopHandler() { flag_updatePWM=true; //force update } +#ifdef DUALCOLOR + float old_temperature = temperature; //store last temperature + if ( (temperature_change_per_loop<0 && temperature>set_temperature) || (temperature_change_per_loop>0 && temperature= set_temperature && set_temperature >= temperature ) ) { //overshot set value + temperature = set_temperature; + } + flag_updatePWM=true; //force update + } +#endif //Sleep if ( (!enable && enable_fadevalue>0) || (enable && enable_fadevalue<1) ) { //not fully turned off or on @@ -210,16 +361,35 @@ void loopHandler() { } //calculate and update pwm +#ifdef DUALCOLOR + if (brightness != set_brightness || temperature != set_temperature || flag_updatePWM) { //if target not reached +#else if (brightness != set_brightness || flag_updatePWM) { //if target not reached +#endif flag_updatePWM=false; // reset flag //calculate pwm values +#ifdef DUALCOLOR + uint16_t pwmCW; + uint16_t pwmWW; + float temp=mapFloat(temperature, TEMPERATURE_MIN, TEMPERATURE_MAX, 0.0,1.0); //0=warmwhite, 1=coldwhite + pwmCW=pow((brightness*enable_fadevalue)/2.0, BRIGHTNESSCURVE) *2.0 *temp *PWM_MAX; //calculate brightness for led stripe, scale to 0-1, ^2, rescale to 0-2, scale for pwm + pwmWW=pow((brightness*enable_fadevalue)/2.0, BRIGHTNESSCURVE) *2.0 *(1-temp) *PWM_MAX; + if (pwmCW>PWM_MAX) { pwmCW=PWM_MAX; } //limit + if (pwmWW>PWM_MAX) { pwmWW=PWM_MAX; } //limit + + analogWrite(LED_WW, PWM_MAX-pwmWW); //full pwm is led off + analogWrite(LED_CW, PWM_MAX-pwmCW); //full pwm is led off +#else uint16_t pwm; pwm=pow((brightness*enable_fadevalue)/2.0, BRIGHTNESSCURVE) *2.0 *PWM_MAX; //calculate brightness for led stripe, scale to 0-1, ^2, rescale to 0-2, scale for pwm - - if (pwm>PWM_MAX) { pwm=PWM_MAX; } //limit analogWrite(LED_PWM, PWM_MAX-pwm); //full pwm is led off +#endif + + + + } } @@ -233,6 +403,12 @@ void loopHandler() { lightNode.setProperty("brightness").send(String(set_brightness)); known_set_brightness=set_brightness; } +#ifdef DUALCOLOR + if (known_set_temperature!=set_temperature) { + lightNode.setProperty("temperature").send(String(set_temperature)); + known_set_temperature=set_temperature; + } +#endif @@ -327,6 +503,33 @@ bool fadetimeHandler(const HomieRange& range, const String& value) { //fadetime return true; } +#ifdef DUALCOLOR +bool temperatureHandler(const HomieRange& range, const String& value) { + if (range.isRange) { + return false; //if range is given but index is not in allowed range + } + Homie.getLogger() << "temperature " << ": " << value << endl; + //lightNode.setProperty("temperature").send(value); //done in main loop + + if (value.toFloat() >= TEMPERATURE_MIN && value.toFloat() <= TEMPERATURE_MAX) { + set_temperature=value.toFloat(); + }else { + Homie.getLogger() << "Value outside range" << endl; + return false; + } + + float _difference=set_temperature-temperature; + if (fadetime>0) { + temperature_change_per_loop = _difference/fadetime*UPDATETIME; + } else { //special case for instant change + temperature_change_per_loop = _difference; + } + + + return true; +} +#endif + bool enableHandler(const HomieRange& range, const String& value) { //change on off if (range.isRange) { return false; //if range is given but index is not in allowed range