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.

1029 lines
28 KiB

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