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.

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