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

  1. /*
  2. LIGHT (EXPERIMENTAL) IR
  3. Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
  4. Copyright (C) 2017 by François Déchery
  5. ------------------------------------------------------------------------------------------
  6. Features :
  7. - ONLY RGB strips are supported (No RGBW or RGBWW)
  8. - IR remote supported (but not mandatory)
  9. - HSV (intuitive) WEB controls
  10. - MQTT & API "color_rgb" + "color_hsv" + "brightness" parameters
  11. - Uses the (amazing) Fastled library for fast and natural Color & Brightness
  12. - Several Animation Modes and Speed (controlled from Remote + Web + MQTT + API)
  13. ------------------------------------------------------------------------------------------
  14. Not currently Implemented :
  15. - Saving/Restoring Settings
  16. - HomeAssistant
  17. ------------------------------------------------------------------------------------------
  18. */
  19. #ifdef LIGHT_PROVIDER_EXPERIMENTAL_RGB_ONLY_HSV_IR
  20. #include <IRremoteESP8266.h>
  21. #include <IRrecv.h>
  22. #include <FastLED.h>
  23. // #### Defined ##########################################################################
  24. #define ANIM_SPEED_STEP 20
  25. #define ANIM1_SPEED 350 // flash ON Variable
  26. #define ANIM1_PAUSE 200 // flash OFF fixed
  27. #define ANIM2_SPEED 550 // strobe OFF variable
  28. #define ANIM2_PAUSE 150 // storbe ON fixed
  29. #define ANIM3_SPEED 100 // fade speed
  30. #define ANIM4_SPEED 700 // smooth speed
  31. #define ANIM5_SPEED 200 // party speed
  32. #define BUTTONS_COUNT 24
  33. #define LED_DURATION 70 // Status led ON duration
  34. // #### Variables ########################################################################
  35. unsigned long r_but_codes[]={ // IR remote buttons codes
  36. IR_BUTTON_0 , // Brightness +
  37. IR_BUTTON_1 , // Brightness -
  38. IR_BUTTON_2 , // OFF
  39. IR_BUTTON_3 , // ON
  40. IR_BUTTON_4 , // Red
  41. IR_BUTTON_5 , // Green
  42. IR_BUTTON_6 , // Blue
  43. IR_BUTTON_7 , // White
  44. IR_BUTTON_8 , // R1
  45. IR_BUTTON_9 , // G1
  46. IR_BUTTON_10 , // B1
  47. IR_BUTTON_11 , // Flash
  48. IR_BUTTON_12 , // R2
  49. IR_BUTTON_13 , // G2
  50. IR_BUTTON_14 , // B2
  51. IR_BUTTON_15 , // Strobe
  52. IR_BUTTON_16 , // R3
  53. IR_BUTTON_17 , // G3
  54. IR_BUTTON_18 , // B3
  55. IR_BUTTON_19 , // Fade
  56. IR_BUTTON_20 , // R4
  57. IR_BUTTON_21 , // G4
  58. IR_BUTTON_22 , // B4
  59. IR_BUTTON_23 // Smooth
  60. };
  61. unsigned long r_but_colors[]={ // IR remote buttons colors
  62. 0, // Brightness +
  63. 0, // Brightness -
  64. 0, // OFF
  65. 0, // ON
  66. 0xFF0000, // Red
  67. 0x00FF00, // Green
  68. 0x0000FF, // Blue
  69. 0xFFFFFF, // White
  70. 0xD13A01, // R1
  71. 0x00E644, // G1
  72. 0x0040A7, // B1
  73. 0, // Flash
  74. 0xE96F2A, // R2
  75. 0x00BEBF, // G2
  76. 0x56406F, // B2
  77. 0, // Strobe
  78. 0xEE9819, // R3
  79. 0x00799A, // G3
  80. 0x944E80, // B3
  81. 0, // Fade
  82. 0xFFFF00, // R4
  83. 0x0060A1, // G4
  84. 0xEF45AD, // B4
  85. 0 // Smooth
  86. };
  87. // variables declarations ###############################################################
  88. CHSV _cur_color = CHSV(0,255,255);
  89. CHSV _cur_anim_color = CHSV(0,0,0);
  90. byte _cur_status = 0 ;
  91. byte _cur_anim_mode = 0 ;
  92. byte _cur_anim_step = 0;
  93. boolean _cur_anim_dir = true;
  94. unsigned long _cur_anim_speed = 1000;
  95. unsigned long _anim_last_update = millis();
  96. unsigned long _last_ir_button = 0;
  97. unsigned long _last_status_led_time = 0;
  98. IRrecv _ir_recv(LIGHT_IR_PIN); //IRrecv _ir_recv(IR_PIN, IR_LED_PIN); dont work. Why ?
  99. decode_results _ir_results;
  100. // #######################################################################################
  101. // #### PRIVATE ##########################################################################
  102. // #######################################################################################
  103. // ---------------------------------------------------------------------------------------
  104. void _updateStatusLed(){
  105. if(millis() > _last_status_led_time + LED_DURATION ){
  106. digitalWrite(LED1_PIN, LOW);
  107. }
  108. }
  109. // ---------------------------------------------------------------------------------------
  110. void _flashStatusLed(){
  111. digitalWrite(LED1_PIN, HIGH);
  112. _last_status_led_time=millis();
  113. }
  114. // ---------------------------------------------------------------------------------------
  115. void _loopProcessIR() {
  116. if (_ir_recv.decode(&_ir_results)) {
  117. //dumpIR(&_ir_results);
  118. //DEBUG_MSG_P(PSTR(".\n"));
  119. unsigned long code = _ir_results.value;
  120. DEBUG_MSG_P(PSTR("[IR] received : 0x%X "), code );
  121. if( code == 0xFFFFFFFF){
  122. code = _last_ir_button;
  123. DEBUG_MSG_P(PSTR("(Repeat : %X) "), code );
  124. }
  125. DEBUG_MSG_P(PSTR("=> ") );
  126. _processIrButtons(code);
  127. _ir_recv.resume(); // Receive the next value
  128. }
  129. }
  130. // ---------------------------------------------------------------------------------------
  131. void _processIrButtons(unsigned long code) {
  132. //DEBUG_MSG_P(PSTR("IR code : %X\n"), code );
  133. boolean done=false;
  134. for (int i = 0; i < BUTTONS_COUNT ; i = i + 1) {
  135. if( code == r_but_codes[i] ){
  136. //DEBUG_MSG_P(PSTR(" : %X -> "), r_but_colors[i] );
  137. _last_ir_button = 0; //no repat else if specified
  138. if(i == 0){
  139. _buttonBrightness(true);
  140. _last_ir_button = code;
  141. delay(150); //debounce
  142. }
  143. else if(i == 1){
  144. _buttonBrightness(false);
  145. _last_ir_button = code;
  146. delay(150); //debounce
  147. }
  148. else if(i == 2){
  149. _buttonPower(false);
  150. }
  151. else if(i == 3){
  152. _buttonPower(true);
  153. }
  154. else if(i == 11){
  155. _buttonAnimMode(1);
  156. }
  157. else if(i == 15){
  158. _buttonAnimMode(2);
  159. }
  160. else if(i == 19){
  161. _buttonAnimMode(3);
  162. }
  163. else if(i == 23){
  164. _buttonAnimMode(4);
  165. }
  166. else{
  167. _buttonColorRVB(r_but_colors[i],0);
  168. }
  169. done=true;
  170. lightUpdate(true, true);
  171. }
  172. }
  173. if(!done){
  174. _last_ir_button = 0;
  175. //DEBUG_PRINTHEX(code);
  176. DEBUG_MSG_P(PSTR("ignored!\n"));
  177. }
  178. }
  179. // ---------------------------------------------------------------------------------------
  180. void _buttonPower(boolean on){
  181. _flashStatusLed();
  182. DEBUG_MSG_P(PSTR("BUT Power: "));
  183. _cur_anim_mode=0;
  184. if(on){
  185. _cur_status=1;
  186. DEBUG_MSG_P(PSTR("ON : "));
  187. _setLedsHSV(_cur_color);
  188. }
  189. else{
  190. _cur_status=0;
  191. DEBUG_MSG_P(PSTR("OFF : "));
  192. _setLedsHSV(CHSV {0,0,0});
  193. }
  194. }
  195. // ---------------------------------------------------------------------------------------
  196. void _buttonAnimMode(byte val){
  197. _flashStatusLed();
  198. DEBUG_MSG_P(PSTR("BUT Anim Mode: %d\n"),val);
  199. _processAnimation(val, true, true);
  200. }
  201. // ---------------------------------------------------------------------------------------
  202. void _setAnimMode(byte val){
  203. DEBUG_MSG_P(PSTR("[LIGHT] Set AnimMode: %d\n"),val);
  204. _processAnimation(val, true, false);
  205. }
  206. // ---------------------------------------------------------------------------------------
  207. void _buttonBrightness(boolean up){
  208. DEBUG_MSG_P(PSTR("BUT Brightness: "));
  209. if(up){
  210. if(_cur_anim_mode==0){
  211. DEBUG_MSG_P(PSTR("UP : "));
  212. _buttonColorHSV(_cur_color, 1 );
  213. }
  214. else{
  215. DEBUG_MSG_P(PSTR("FASTER\n"));
  216. _buttonChangeSpeed( - ANIM_SPEED_STEP );
  217. }
  218. }
  219. else{
  220. if(_cur_anim_mode==0){
  221. DEBUG_MSG_P(PSTR("DOWN : "));
  222. _buttonColorHSV(_cur_color, -1 );
  223. }
  224. else{
  225. DEBUG_MSG_P(PSTR("SLOWER\n"));
  226. _buttonChangeSpeed( ANIM_SPEED_STEP );
  227. }
  228. }
  229. }
  230. // ---------------------------------------------------------------------------------------
  231. void _buttonColorHSV(CHSV color, int offset){
  232. _flashStatusLed();
  233. DEBUG_MSG_P(PSTR("[LIGHT] Set Color to : "));
  234. //DEBUG_MSG_P(PSTR("(from HSV=%d,%d,%d) "), color.h, color.s, color.v);
  235. color=_dimHSV(color,offset);
  236. //DEBUG_MSG_P(PSTR("(to HSV=%d,%d,%d) "), color.h, color.s, color.v);
  237. _setLedsHSV(color);
  238. if(color.v ==0 ){
  239. _cur_status=0;
  240. }
  241. else{
  242. _cur_status=1;
  243. }
  244. _cur_color=color;
  245. _romSaveCurrentColor();
  246. }
  247. // ---------------------------------------------------------------------------------------
  248. void _buttonColorRVB(CRGB color, int offset){
  249. _buttonColorHSV(_rgbToHsv(color), offset);
  250. }
  251. // ---------------------------------------------------------------------------------------
  252. void _buttonChangeSpeed(int offset){
  253. _flashStatusLed();
  254. if(offset !=0){
  255. _cur_anim_speed=_cur_anim_speed + offset ;
  256. }
  257. }
  258. // ---------------------------------------------------------------------------------------
  259. CHSV _dimHSV(CHSV color, int offset){
  260. offset=offset*10;
  261. int bright=color.v + offset;
  262. if(offset ==0){
  263. return color;
  264. }
  265. else if(bright < 1){
  266. bright=1; // no off
  267. }
  268. else if(bright > 255){
  269. bright=255;
  270. }
  271. color.v=bright;
  272. return color;
  273. }
  274. // ---------------------------------------------------------------------------------------
  275. void _setBrightnessMapped(byte val){
  276. DEBUG_MSG_P(PSTR("[LIGHT] Set from 0-100 Brightness : %u => "), val);
  277. val =map(val,0,100,0,255);
  278. _setBrightness(val);
  279. }
  280. // ---------------------------------------------------------------------------------------
  281. void _setBrightness(byte val){
  282. DEBUG_MSG_P(PSTR("[LIGHT] Set Brightness to : %u\n"), val);
  283. _cur_color.v = val;
  284. _cur_anim_color.v = val;
  285. if(val==0){
  286. _cur_status=0;
  287. }
  288. _buttonColorHSV(_cur_color,0);
  289. }
  290. // ---------------------------------------------------------------------------------------
  291. void _setAnimSpeed(unsigned long speed){
  292. if(speed !=0){
  293. _cur_anim_speed=speed ;
  294. }
  295. }
  296. // ---------------------------------------------------------------------------------------
  297. void _setLedsRGB(CRGB rgb){
  298. analogWrite(LIGHT_CH1_PIN, rgb.r);
  299. analogWrite(LIGHT_CH2_PIN, rgb.g);
  300. analogWrite(LIGHT_CH3_PIN, rgb.b);
  301. if(_cur_anim_mode == 0){
  302. DEBUG_MSG_P(PSTR("RGB=%3u,%3u,%3u\n"), rgb.r, rgb.g, rgb.b);
  303. }
  304. }
  305. // ---------------------------------------------------------------------------------------
  306. void _setLedsHSV(CHSV hsv){
  307. if(_cur_anim_mode == 0){
  308. DEBUG_MSG_P(PSTR("HSV=%3u,%3u,%3u - "), hsv.h, hsv.s, hsv.v);
  309. }
  310. _setLedsRGB( CHSV(hsv) );
  311. }
  312. // ---------------------------------------------------------------------------------------
  313. void _confirmFlash(){
  314. _setLedsRGB(CRGB::Black);
  315. delay(70);
  316. _setLedsRGB(CRGB::White);
  317. delay(70);
  318. _setLedsRGB(CRGB::Black);
  319. delay(70);
  320. _setLedsRGB(CRGB::White);
  321. delay(70);
  322. _setLedsRGB(CRGB::Black);
  323. delay(70);
  324. }
  325. // ---------------------------------------------------------------------------------------
  326. void _processAnimation(byte mode, boolean init, boolean is_button){
  327. if(init){
  328. if(_cur_anim_mode == mode && is_button){
  329. _confirmFlash();
  330. DEBUG_MSG_P(PSTR("[ANIM_%d] Stopped !!!\n"), mode);
  331. _cur_anim_mode=0;
  332. _cur_status=0;
  333. return;
  334. }
  335. else if(mode == 0){
  336. DEBUG_MSG_P(PSTR("[ANIM_%d] Stopped !!!\n"), mode);
  337. _cur_anim_mode=0;
  338. _cur_status=0;
  339. return;
  340. }
  341. else{
  342. if(is_button){
  343. _confirmFlash();
  344. }
  345. DEBUG_MSG_P(PSTR("[ANIM_%d] Started !!!\n"), mode);
  346. }
  347. }
  348. if(mode==1){
  349. _anim1(init);
  350. }
  351. else if(mode==2){
  352. _anim2(init);
  353. }
  354. else if(mode==3){
  355. _anim3(init);
  356. }
  357. else if(mode==4){
  358. _anim4(init);
  359. }
  360. else if(mode==5){
  361. _anim5(init);
  362. }
  363. else{
  364. //invalid mode
  365. }
  366. }
  367. // ---------------------------------------------------------------------------------------
  368. // anim1 : flash
  369. void _anim1(boolean init){
  370. if(init){
  371. _cur_anim_mode = 1;
  372. _cur_anim_speed = ANIM1_SPEED;
  373. _cur_status = 1;
  374. _cur_anim_step = 1;
  375. }
  376. unsigned long now= millis();
  377. if(_cur_anim_step==1 && now > (_anim_last_update + _cur_anim_speed) ){
  378. //DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
  379. _setLedsHSV(_cur_color);
  380. _cur_anim_step=0;
  381. _anim_last_update = now;
  382. }
  383. else if(_cur_anim_step==0 && now > (_anim_last_update + ANIM1_PAUSE) ){
  384. //DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
  385. _setLedsHSV(CHSV {0,0,0});
  386. _cur_anim_step=1;
  387. _anim_last_update = now;
  388. }
  389. }
  390. // ---------------------------------------------------------------------------------------
  391. // anim2 : strobe
  392. void _anim2(boolean init){
  393. if(init){
  394. _cur_anim_mode = 2;
  395. _cur_anim_speed = ANIM2_SPEED;
  396. _cur_status = 1;
  397. _cur_anim_step = 1;
  398. }
  399. unsigned long now= millis();
  400. if(_cur_anim_step==1 && now > (_anim_last_update + ANIM2_PAUSE) ){
  401. //DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
  402. _setLedsHSV(_cur_color);
  403. _cur_anim_step=0;
  404. _anim_last_update = now;
  405. }
  406. else if(_cur_anim_step==0 && now > (_anim_last_update + _cur_anim_speed) ){
  407. //DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
  408. _setLedsHSV(CHSV {0,0,0});
  409. _cur_anim_step=1;
  410. _anim_last_update = now;
  411. }
  412. }
  413. // ---------------------------------------------------------------------------------------
  414. // anim3 : fade
  415. void _anim3(boolean init){
  416. if(init){
  417. _cur_anim_mode = 3;
  418. _cur_anim_speed = ANIM3_SPEED;
  419. _cur_status = 1;
  420. _cur_anim_step = _cur_color.v;
  421. }
  422. unsigned long now= millis();
  423. if( now > (_anim_last_update + _cur_anim_speed) ){
  424. //DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
  425. _setLedsHSV( CHSV(_cur_color.h, _cur_color.s, dim8_lin(_cur_anim_step)) );
  426. if(_cur_anim_dir){
  427. if(_cur_anim_step == 255){
  428. _cur_anim_dir=false;
  429. }
  430. else{
  431. _cur_anim_step++;
  432. }
  433. }
  434. else{
  435. if(_cur_anim_step == 1){
  436. _cur_anim_dir=true;
  437. }
  438. else{
  439. _cur_anim_step--;
  440. }
  441. }
  442. _anim_last_update = now;
  443. }
  444. }
  445. // ---------------------------------------------------------------------------------------
  446. // anim4 : smooth
  447. void _anim4(boolean init){
  448. if(init){
  449. _cur_anim_mode = 4;
  450. _cur_anim_speed = ANIM4_SPEED;
  451. _cur_status = 1;
  452. _cur_anim_step = 0;
  453. _cur_anim_color = _cur_color;
  454. _cur_anim_color.v = 255;
  455. }
  456. unsigned long now= millis();
  457. if( now > (_anim_last_update + _cur_anim_speed) ){
  458. //DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
  459. _cur_anim_color.h=_cur_anim_step;
  460. _cur_anim_color.s=255;
  461. _setLedsHSV( CHSV(_cur_anim_step,255,255) );
  462. _cur_anim_step++;
  463. _anim_last_update = now;
  464. if(_cur_anim_step > 255){
  465. _cur_anim_step=0;
  466. }
  467. }
  468. }
  469. // ---------------------------------------------------------------------------------------
  470. // anim5 : party
  471. void _anim5(boolean init){
  472. if(init){
  473. _cur_anim_mode = 5;
  474. _cur_anim_speed = ANIM5_SPEED;
  475. _cur_status = 1;
  476. _cur_anim_step = 0;
  477. _cur_anim_color = _cur_color;
  478. _cur_anim_color.s= 255;
  479. _cur_anim_color.v= 255;
  480. }
  481. unsigned long now= millis();
  482. if(_cur_anim_step == 1 && now > (_anim_last_update + _cur_anim_speed) ){
  483. DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
  484. _cur_anim_color.h = random(0,255);
  485. _setLedsHSV(_cur_anim_color);
  486. _cur_anim_step = 0;
  487. _anim_last_update = now;
  488. }
  489. else if(_cur_anim_step==0 && now > (_anim_last_update + _cur_anim_speed + 15) ){
  490. //DEBUG_MSG_P(PSTR("[ANIM_%d] Update : "), _cur_anim_mode);
  491. _setLedsHSV(CHSV {0,0,0});
  492. _cur_anim_step = 1;
  493. _anim_last_update = now;
  494. }
  495. }
  496. // ---------------------------------------------------------------------------------------
  497. void _loopUpdateAnimation(){
  498. _processAnimation(_cur_anim_mode, false, false);
  499. }
  500. // ---------------------------------------------------------------------------------------
  501. CHSV _rgbToHsv(CRGB rgb){
  502. /*
  503. if(rgb.r <=1 && rgb.g <=1 && rgb.b <=1){
  504. DEBUG_MSG_P(PSTR(" {Rounding RGB to black} "));
  505. return CHSV {0,0,0};
  506. }
  507. */
  508. return rgb2hsv_approximate(rgb);
  509. }
  510. // ---------------------------------------------------------------------------------------
  511. void _romSaveCurrentColor(){
  512. //save it to 1,2,3 positions
  513. //but dont stress eeprom if not needed
  514. /*
  515. CHSV rom =_romLoadColor();
  516. if(_cur_color.h != rom.h){gw.saveState(1,_cur_color.h);}
  517. if(_cur_color.s != rom.s){gw.saveState(2,_cur_color.s);}
  518. if(_cur_color.v != rom.v){gw.saveState(3,_cur_color.v);}
  519. */
  520. }
  521. // ---------------------------------------------------------------------------------------
  522. CHSV _romLoadColor(){
  523. //load from 1,2,3 positions
  524. CHSV color;
  525. /*
  526. color.h=gw.loadState(1);
  527. color.s=gw.loadState(2);
  528. color.v=gw.loadState(3);
  529. */
  530. return color;
  531. }
  532. // ----------------------------------------------
  533. CRGB _longToRgb(unsigned long rgb){
  534. CRGB out;
  535. out.r = rgb >> 16;
  536. out.g = rgb >> 8 & 0xFF;
  537. out.b = rgb & 0xFF;
  538. return out;
  539. }
  540. // ---------------------------------------------------------------------------------------
  541. CHSV _longToHsv(unsigned long hsv){
  542. CHSV out;
  543. out.h = hsv >> 16;
  544. out.s = hsv >> 8 & 0xFF;
  545. out.v = hsv & 0xFF;
  546. return out;
  547. }
  548. // ---------------------------------------------------------------------------------------
  549. unsigned long _rgbToLong(CRGB in){
  550. return (((long)in.r & 0xFF) << 16) + (((long)in.g & 0xFF) << 8) + ((long)in.b & 0xFF);
  551. }
  552. // ---------------------------------------------------------------------------------------
  553. unsigned long _hsvToLong(CHSV in){
  554. return (((long)in.h & 0xFF) << 16) + (((long)in.s & 0xFF) << 8) + ((long)in.v & 0xFF);
  555. }
  556. // ---------------------------------------------------------------------------------------
  557. CRGB _charToRgb(const char * rgb) {
  558. char * p = (char *) rgb;
  559. // if color begins with a # then assume HEX RGB
  560. if (p[0] == '#') {
  561. ++p;
  562. }
  563. return _longToRgb( strtoul(p, NULL, 16) );
  564. }
  565. // ---------------------------------------------------------------------------------------
  566. CHSV _charToHsv(const char * rgb) {
  567. char * p = (char *) rgb;
  568. // if color begins with a # then assume HEX RGB
  569. if (p[0] == '#') {
  570. ++p;
  571. }
  572. return _longToHsv( strtoul(p, NULL, 16) );
  573. }
  574. // ---------------------------------------------------------------------------------------
  575. boolean _charColorIsValid(const char * rgb){
  576. char * p = (char *) rgb;
  577. if (strlen(p) == 6 || strlen(p) == 7 ){
  578. return true;
  579. }
  580. return false;
  581. }
  582. // ---------------------------------------------------------------------------------------
  583. void _CurrentColorToRGB(char * buffer) {
  584. snprintf_P(buffer, 8, PSTR("%06X"), _rgbToLong( CHSV(_cur_color)));
  585. }
  586. // ---------------------------------------------------------------------------------------
  587. void _CurrentColorToHSV(char * buffer) {
  588. snprintf_P(buffer, 8, PSTR("%06X"), _hsvToLong( _cur_color));
  589. }
  590. // ---------------------------------------------------------------------------------------
  591. void _lightColorRestore() {
  592. /*
  593. for (unsigned int i=0; i < _channels.size(); i++) {
  594. _channels[i].value = getSetting("ch", i, 0).toInt();
  595. }
  596. _brightness = getSetting("brightness", LIGHT_MAX_BRIGHTNESS).toInt();
  597. lightUpdate(false, false);
  598. */
  599. }
  600. // ---------------------------------------------------------------------------------------
  601. void _lightAPISetup() {
  602. #if WEB_SUPPORT
  603. // API entry points (protected with apikey)
  604. if (lightHasColor()) {
  605. apiRegister(MQTT_TOPIC_COLOR_RGB, MQTT_TOPIC_COLOR_RGB,
  606. [](char * buffer, size_t len) {
  607. _CurrentColorToRGB(buffer);
  608. },
  609. [](const char * payload) {
  610. _SetLightColorRGB(payload);
  611. lightUpdate(true, true);
  612. }
  613. );
  614. apiRegister(MQTT_TOPIC_COLOR_HSV, MQTT_TOPIC_COLOR_HSV,
  615. [](char * buffer, size_t len) {
  616. _CurrentColorToHSV(buffer);
  617. },
  618. [](const char * payload) {
  619. _SetLightColorHSV(payload);
  620. lightUpdate(true, true);
  621. }
  622. );
  623. apiRegister(MQTT_TOPIC_BRIGHTNESS, MQTT_TOPIC_BRIGHTNESS,
  624. [](char * buffer, size_t len) {
  625. snprintf_P(buffer, len, PSTR("%d"), _cur_color.v);
  626. },
  627. [](const char * payload) {
  628. _setBrightness(atoi(payload));
  629. lightUpdate(true, true);
  630. }
  631. );
  632. apiRegister(MQTT_TOPIC_ANIM_MODE, MQTT_TOPIC_ANIM_MODE,
  633. [](char * buffer, size_t len) {
  634. snprintf_P(buffer, len, PSTR("%d"), _cur_anim_mode);
  635. },
  636. [](const char * payload) {
  637. _setAnimMode(atoi(payload));
  638. lightUpdate(true, true);
  639. }
  640. );
  641. apiRegister(MQTT_TOPIC_ANIM_SPEED, MQTT_TOPIC_ANIM_SPEED,
  642. [](char * buffer, size_t len) {
  643. snprintf_P(buffer, len, PSTR("%d"), _cur_anim_speed);
  644. },
  645. [](const char * payload) {
  646. _setAnimSpeed(atoi(payload));
  647. lightUpdate(true, true);
  648. }
  649. );
  650. }
  651. /*
  652. for (unsigned int id=0; id<lightChannels(); id++) {
  653. char url[15];
  654. snprintf_P(url, sizeof(url), PSTR("%s/%d"), MQTT_TOPIC_CHANNEL, id);
  655. char key[10];
  656. snprintf_P(key, sizeof(key), PSTR("%s%d"), MQTT_TOPIC_CHANNEL, id);
  657. apiRegister(url, key,
  658. [id](char * buffer, size_t len) {
  659. snprintf_P(buffer, len, PSTR("%d"), lightChannel(id));
  660. },
  661. [id](const char * payload) {
  662. lightChannel(id, atoi(payload));
  663. lightUpdate(true, true);
  664. }
  665. );
  666. }
  667. */
  668. #endif // WEB_SUPPORT
  669. }
  670. /*
  671. // #######################################################################################
  672. // ---------------------------------------------------------------------------------------
  673. CRGB _hsvToRgb(CHSV hsv){
  674. if(hsv.v <=1){
  675. DEBUG_MSG_P(PSTR(" {Rounding HSV to black}\n"));
  676. hsv.v=0;
  677. }
  678. CRGB rgb=CHSV(hsv);
  679. //round to black
  680. if(rgb.r <=1 && rgb.g <=1 && rgb.b <=1){
  681. DEBUG_MSG_P(PSTR(" {Rounding RGB to black}\n"));
  682. rgb=CRGB::Black;
  683. }
  684. return rgb;
  685. }
  686. // ---------------------------------------------------------------------------------------
  687. void _strToUpper(char * str){
  688. for(int i=0; i<6; i++){
  689. //a-z
  690. if (97<=str[i]&&str[i]<=122){
  691. str[i]-=32;
  692. }
  693. }
  694. }
  695. */
  696. // #######################################################################################
  697. // #### PUBLIC ###########################################################################
  698. // #######################################################################################
  699. // ################################################################
  700. void lightSetup() {
  701. DEBUG_MSG_P(PSTR("[LIGHT] LIGHT_PROVIDER = %d (With IR)\n"), LIGHT_PROVIDER);
  702. pinMode(LIGHT_CH1_PIN, OUTPUT);
  703. pinMode(LIGHT_CH2_PIN, OUTPUT);
  704. pinMode(LIGHT_CH3_PIN, OUTPUT);
  705. _ir_recv.enableIRIn(); // Start the receiver
  706. //confirmRgb();
  707. _cur_color = _romLoadColor();
  708. _lightColorRestore();
  709. _lightAPISetup();
  710. mqttRegister(_lightMQTTCallback);
  711. }
  712. // ---------------------------------------------------------------------------------------
  713. void lightLoop() {
  714. _loopProcessIR();
  715. _loopUpdateAnimation();
  716. _updateStatusLed();
  717. }
  718. // ---------------------------------------------------------------------------------------
  719. void lightUpdate(bool save, bool forward) {
  720. //DEBUG_MSG_P(PSTR("[LIGHT] Updating... \n"));
  721. // _lightProviderUpdate();
  722. // Report color & brightness to MQTT broker
  723. if (forward) lightMQTT();
  724. // Report color to WS clients (using current brightness setting)
  725. #if WEB_SUPPORT
  726. {
  727. DynamicJsonBuffer jsonBuffer;
  728. JsonObject& root = jsonBuffer.createObject();
  729. root["colorVisible"] = 1;
  730. root["useColor"] = getSetting("useColor", LIGHT_USE_COLOR).toInt() == 1;
  731. root["useWhite"] = getSetting("useWhite", LIGHT_USE_WHITE).toInt() == 1;
  732. root["useGamma"] = getSetting("useGamma", LIGHT_USE_GAMMA).toInt() == 1;
  733. root["anim_mode"] = lightAnimMode();
  734. root["anim_speed"] = lightAnimSpeed();
  735. JsonObject& color_hsv = root.createNestedObject("color_hsv");
  736. color_hsv["h"] = lightColorH();
  737. color_hsv["s"] = lightColorS();
  738. color_hsv["v"] = lightColorV();
  739. //root["color_hsv"] = lightColor();
  740. //root["brightness"] = _cur_color.v;
  741. // RGB channels
  742. //JsonArray& channels = root.createNestedArray("channels");
  743. //for (unsigned char id=0; id < lightChannels(); id++) {
  744. // channels.add(lightChannel(id));
  745. //}
  746. // Relay
  747. JsonArray& relay = root.createNestedArray("relayStatus");
  748. relay.add(_cur_status);
  749. String output;
  750. root.printTo(output);
  751. wsSend(output.c_str());
  752. //DEBUG_MSG_P(PSTR("JSON : %s"), output.c_str() );
  753. }
  754. #endif
  755. // Delay saving to EEPROM 5 seconds to avoid wearing it out unnecessarily
  756. //if (save) colorTicker.once(LIGHT_SAVE_DELAY, _lightColorSave);
  757. }
  758. // ---------------------------------------------------------------------------------------
  759. void lightMQTT() {
  760. char buffer[8];
  761. if (lightHasColor()) {
  762. // RGB Color
  763. _CurrentColorToRGB(buffer);
  764. mqttSend(MQTT_TOPIC_COLOR_RGB, buffer);
  765. // HSV Color
  766. _CurrentColorToHSV(buffer);
  767. mqttSend(MQTT_TOPIC_COLOR_HSV, buffer);
  768. // Brightness
  769. snprintf_P(buffer, sizeof(buffer), PSTR("%d"), _cur_color.v);
  770. mqttSend(MQTT_TOPIC_BRIGHTNESS, buffer);
  771. // Anim Mode
  772. snprintf_P(buffer, sizeof(buffer), PSTR("%d"), _cur_anim_mode);
  773. mqttSend(MQTT_TOPIC_ANIM_MODE, buffer);
  774. // Anim Speed
  775. snprintf_P(buffer, sizeof(buffer), PSTR("%d"), _cur_anim_speed);
  776. mqttSend(MQTT_TOPIC_ANIM_SPEED, buffer);
  777. }
  778. // Channels
  779. //for (unsigned int i=0; i < _channels.size(); i++) {
  780. // snprintf_P(buffer, sizeof(buffer), PSTR("%d"), _channels[i].value);
  781. // mqttSend(MQTT_TOPIC_CHANNEL, i, buffer);
  782. //}
  783. }
  784. // ---------------------------------------------------------------------------------------
  785. // Get Number of Channels
  786. unsigned char lightChannels() {
  787. return 3;
  788. }
  789. // ---------------------------------------------------------------------------------------
  790. // Get Channel's Value
  791. unsigned int lightChannel(unsigned char id) {
  792. CRGB current_rvb = CHSV(_cur_color);
  793. if(id == 0 ){
  794. return current_rvb.r;
  795. }
  796. else if(id == 1 ){
  797. return current_rvb.g;
  798. }
  799. else if(id == 2 ){
  800. return current_rvb.b;
  801. }
  802. else{
  803. DEBUG_MSG_P(PSTR(" [ERROR] GET lightChannel : %s\n"), id);
  804. return 0;
  805. }
  806. }
  807. // ---------------------------------------------------------------------------------------
  808. // Set Channel's Value
  809. void lightChannel(unsigned char id, unsigned int value) {
  810. DEBUG_MSG_P(PSTR("[WEB|API] Set Color Channel "));
  811. value= constrain(value, 0, 255);
  812. CRGB current_rvb = CHSV(_cur_color);
  813. if(id == 0 ){
  814. DEBUG_MSG_P(PSTR("RED to : %d => "), value);
  815. current_rvb.r=value;
  816. _buttonColorRVB(current_rvb,0);
  817. }
  818. else if(id == 1 ){
  819. DEBUG_MSG_P(PSTR("GREEN to : %d => "), value);
  820. current_rvb.g=value;
  821. _buttonColorRVB(current_rvb,0);
  822. }
  823. else if(id == 2 ){
  824. DEBUG_MSG_P(PSTR("BLUE to : %d => "), value);
  825. current_rvb.b=value;
  826. _buttonColorRVB(current_rvb,0);
  827. }
  828. else{
  829. DEBUG_MSG_P(PSTR(" [ERROR] SET lightChannel %s To %d \n"), id, value);
  830. }
  831. }
  832. // ---------------------------------------------------------------------------------------
  833. // Get Brightness
  834. unsigned int lightBrightness() {
  835. return _cur_color.v;
  836. }
  837. // ---------------------------------------------------------------------------------------
  838. // Set Brightness
  839. void lightBrightness(unsigned int b) {
  840. b=constrain(b, 0, 255);
  841. DEBUG_MSG_P(PSTR("[WEB|API] Set Brightness to : %d\n"), b);
  842. _cur_color.v=b;
  843. _setLedsHSV(_cur_color);
  844. //set status
  845. if(b > 0){
  846. _cur_status=1;
  847. }
  848. else{
  849. _cur_status=0;
  850. }
  851. }
  852. // ---------------------------------------------------------------------------------------
  853. // Get Color
  854. String lightColor() {
  855. char rgb[8];
  856. snprintf_P(rgb, 8, PSTR("#%06X"), _rgbToLong( CHSV(_cur_color)));
  857. return String(rgb);
  858. //return String("");
  859. }
  860. String lightColorH(){
  861. return String(_cur_color.h);
  862. }
  863. String lightColorS(){
  864. return String(_cur_color.s);
  865. }
  866. String lightColorV(){
  867. return String(_cur_color.v);
  868. }
  869. // ---------------------------------------------------------------------------------------
  870. // Set Color
  871. void lightColor(const char * color) {
  872. //used only from settings
  873. _SetLightColorRGB(color);
  874. }
  875. void _SetLightColorRGB(const char * color) {
  876. //used only from settings
  877. DEBUG_MSG_P(PSTR("[WEB|API] Set (#RGB) Color to : "));
  878. if( _charColorIsValid(color) ){
  879. DEBUG_MSG_P(PSTR("%s \n"), color);
  880. _buttonColorRVB(_charToRgb(color), 0);
  881. }
  882. else{
  883. DEBUG_MSG_P(PSTR(" Canceled ('%s' is invalid) !\n"), color);
  884. }
  885. }
  886. void _SetLightColorHSV(const char * color) {
  887. DEBUG_MSG_P(PSTR("[WEB|API] Set (#HSV) Color to : "));
  888. if( _charColorIsValid(color) ){
  889. DEBUG_MSG_P(PSTR("%s \n"), color);
  890. _buttonColorHSV(_charToHsv(color), 0);
  891. }
  892. else{
  893. DEBUG_MSG_P(PSTR(" Canceled ('%s' is invalid) !\n"), color);
  894. }
  895. }
  896. void setLightColor (const char * h, const char * s, const char * v){
  897. DEBUG_MSG_P(PSTR("[WEB|API] Set Color from (%s,%s,%s) "), h, s, v);
  898. CHSV color;
  899. color.h=strtoul(h, NULL, 10);
  900. color.s=strtoul(s, NULL, 10);
  901. color.v=strtoul(v, NULL, 10);
  902. DEBUG_MSG_P(PSTR("to (%d,%d,%d) "), color.h, color.s, color.v);
  903. _buttonColorRVB(color, 0);
  904. }
  905. // ---------------------------------------------------------------------------------------
  906. bool lightHasColor() {
  907. // bool useColor = getSetting("useColor", LIGHT_USE_COLOR).toInt() == 1;
  908. // return useColor && (_channels.size() > 2);
  909. //if(_cur_status || _cur_anim_mode){return 1;}
  910. return true;
  911. }
  912. // ---------------------------------------------------------------------------------------
  913. // Get State
  914. bool lightState() {
  915. //DEBUG_MSG_P(PSTR("[->LIGHT] _cur_status is : %d \n"),_cur_status);
  916. return _cur_status;
  917. }
  918. // ---------------------------------------------------------------------------------------
  919. // Set State
  920. void lightState(bool state){
  921. DEBUG_MSG_P(PSTR("[WEB|API] Set Relay to : %u => "), state);
  922. //if(state != _cur_status){
  923. _buttonPower(state);
  924. //}
  925. }
  926. // ---------------------------------------------------------------------------------------
  927. String lightAnimMode(){
  928. return String(_cur_anim_mode);
  929. }
  930. void lightAnimMode(const char * val){
  931. DEBUG_MSG_P(PSTR("[WEB|API] Set AnimMode to %s\n"), val);
  932. _setAnimMode(strtoul(val, NULL, 10));
  933. }
  934. // ---------------------------------------------------------------------------------------
  935. String lightAnimSpeed(){
  936. return String(_cur_anim_speed);
  937. }
  938. void lightAnimSpeed(const char * val){
  939. DEBUG_MSG_P(PSTR("[WEB|API] Set AnimSpeed to %s \n"), val);
  940. _setAnimSpeed(strtoul(val, NULL, 10));
  941. }
  942. // ---------------------------------------------------------------------------------------
  943. // MQTT
  944. // ---------------------------------------------------------------------------------------
  945. void _lightMQTTCallback(unsigned int type, const char * topic, const char * payload) {
  946. if (type == MQTT_CONNECT_EVENT) {
  947. if (lightHasColor()) {
  948. mqttSubscribe(MQTT_TOPIC_BRIGHTNESS);
  949. mqttSubscribe(MQTT_TOPIC_COLOR_RGB);
  950. mqttSubscribe(MQTT_TOPIC_COLOR_HSV);
  951. mqttSubscribe(MQTT_TOPIC_ANIM_MODE);
  952. mqttSubscribe(MQTT_TOPIC_ANIM_SPEED);
  953. }
  954. //char buffer[strlen(MQTT_TOPIC_CHANNEL) + 3];
  955. //snprintf_P(buffer, sizeof(buffer), PSTR("%s/+"), MQTT_TOPIC_CHANNEL);
  956. //mqttSubscribe(buffer);
  957. }
  958. if (type == MQTT_MESSAGE_EVENT) {
  959. // Match topic
  960. String t = mqttSubtopic((char *) topic);
  961. // Color RGB
  962. if (t.equals(MQTT_TOPIC_COLOR_RGB)) {
  963. _SetLightColorRGB(payload);
  964. lightUpdate(true, mqttForward());
  965. }
  966. // Color HSV
  967. if (t.equals(MQTT_TOPIC_COLOR_HSV)) {
  968. _SetLightColorHSV(payload);
  969. lightUpdate(true, mqttForward());
  970. }
  971. // ANIM Mode
  972. if (t.equals(MQTT_TOPIC_ANIM_MODE)) {
  973. _setAnimMode(atoi(payload));
  974. lightUpdate(true, mqttForward());
  975. }
  976. // ANIM Speed
  977. if (t.equals(MQTT_TOPIC_ANIM_SPEED)) {
  978. _setAnimSpeed(atoi(payload));
  979. lightUpdate(true, mqttForward());
  980. }
  981. // Brightness
  982. if (t.equals(MQTT_TOPIC_BRIGHTNESS)) {
  983. _setBrightness (constrain(atoi(payload), 0, LIGHT_MAX_BRIGHTNESS));
  984. lightUpdate(true, mqttForward());
  985. }
  986. /*
  987. // Channel
  988. if (t.startsWith(MQTT_TOPIC_CHANNEL)) {
  989. unsigned int channelID = t.substring(strlen(MQTT_TOPIC_CHANNEL)+1).toInt();
  990. if (channelID >= _channels.size()) {
  991. DEBUG_MSG_P(PSTR("[LIGHT] Wrong channelID (%d)\n"), channelID);
  992. return;
  993. }
  994. lightChannel(channelID, atoi(payload));
  995. lightUpdate(true, mqttForward());
  996. }
  997. */
  998. }
  999. }
  1000. #endif // LIGHT_IR_PIN