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.

209 lines
5.7 KiB

  1. /*
  2. LIGHT MODULE
  3. Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
  6. #include <Ticker.h>
  7. Ticker colorTicker;
  8. bool _lightState = false;
  9. unsigned int _lightColor[3] = {0};
  10. #if LIGHT_PROVIDER == LIGHT_PROVIDER_MY9192
  11. #include <my9291.h>
  12. my9291 * _my9291;
  13. #endif
  14. // -----------------------------------------------------------------------------
  15. // UTILS
  16. // -----------------------------------------------------------------------------
  17. void color_rgb2array(const char * rgb, unsigned int * array) {
  18. char * p = (char *) rgb;
  19. if (p[0] == '#') ++p;
  20. unsigned long value = strtol(p, NULL, 16);
  21. array[0] = (value >> 16) & 0xFF;
  22. array[1] = (value >> 8) & 0xFF;
  23. array[2] = (value) & 0xFF;
  24. }
  25. void color_array2rgb(unsigned int * array, char * rgb) {
  26. unsigned long value = array[0];
  27. value = (value << 8) + array[1];
  28. value = (value << 8) + array[2];
  29. sprintf(rgb, "#%06X", value);
  30. }
  31. // -----------------------------------------------------------------------------
  32. // PROVIDER
  33. // -----------------------------------------------------------------------------
  34. void lightColorProvider(unsigned int red, unsigned int green, unsigned int blue) {
  35. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_MY9192) || (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  36. unsigned int white = 0;
  37. // If all set to the same value use white instead
  38. if ((red == green) && (green == blue)) {
  39. white = red;
  40. red = green = blue = 0;
  41. }
  42. #endif
  43. #if LIGHT_PROVIDER == LIGHT_PROVIDER_MY9192
  44. _my9291->setColor((my9291_color_t) { red, green, blue, white });
  45. #endif
  46. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_RGB) || (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  47. if (RGBW_INVERSE_LOGIC) {
  48. analogWrite(RGBW_RED_PIN, red);
  49. analogWrite(RGBW_GREEN_PIN, green);
  50. analogWrite(RGBW_BLUE_PIN, blue);
  51. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  52. analogWrite(RGBW_WHITE_PIN, white);
  53. #endif
  54. } else {
  55. analogWrite(RGBW_RED_PIN, 255 - red);
  56. analogWrite(RGBW_GREEN_PIN, 255 - green);
  57. analogWrite(RGBW_BLUE_PIN, 255 - blue);
  58. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  59. analogWrite(RGBW_WHITE_PIN, 255 - white);
  60. #endif
  61. }
  62. #endif
  63. }
  64. // -----------------------------------------------------------------------------
  65. // LIGHT MANAGEMENT
  66. // -----------------------------------------------------------------------------
  67. void lightColor(const char * rgb, bool save, bool forward) {
  68. color_rgb2array(rgb, _lightColor);
  69. lightColorProvider(_lightColor[0], _lightColor[1], _lightColor[2]);
  70. // Delay saving to EEPROM 5 seconds to avoid wearing it out unnecessarily
  71. if (save) colorTicker.once(LIGHT_SAVE_DELAY, lightColorSave);
  72. // Report color to MQTT broker
  73. if (forward) mqttSend(MQTT_TOPIC_COLOR, rgb);
  74. // Report color to WS clients
  75. char message[20];
  76. sprintf(message, "{\"color\": \"%s\"}", rgb);
  77. wsSend(message);
  78. }
  79. String lightColor() {
  80. char rgb[8];
  81. color_array2rgb(_lightColor, rgb);
  82. return String(rgb);
  83. }
  84. void lightState(bool state) {
  85. if (state) {
  86. lightColorProvider(_lightColor[0], _lightColor[1], _lightColor[2]);
  87. } else {
  88. lightColorProvider(0, 0, 0);
  89. }
  90. _lightState = state;
  91. }
  92. bool lightState() {
  93. return _lightState;
  94. }
  95. // -----------------------------------------------------------------------------
  96. // PERSISTANCE
  97. // -----------------------------------------------------------------------------
  98. void lightColorSave() {
  99. setSetting("color", lightColor());
  100. saveSettings();
  101. }
  102. void lightColorRetrieve() {
  103. lightColor(getSetting("color", LIGHT_DEFAULT_COLOR).c_str(), false, true);
  104. }
  105. // -----------------------------------------------------------------------------
  106. // MQTT
  107. // -----------------------------------------------------------------------------
  108. void lightMQTTCallback(unsigned int type, const char * topic, const char * payload) {
  109. if (type == MQTT_CONNECT_EVENT) {
  110. mqttSubscribe(MQTT_TOPIC_COLOR);
  111. }
  112. if (type == MQTT_MESSAGE_EVENT) {
  113. // Match topic
  114. String t = mqttSubtopic((char *) topic);
  115. if (!t.equals(MQTT_TOPIC_COLOR)) return;
  116. lightColor(payload, true, mqttForward());
  117. }
  118. }
  119. //------------------------------------------------------------------------------
  120. // REST API
  121. //------------------------------------------------------------------------------
  122. void lightSetupAPI() {
  123. // API entry points (protected with apikey)
  124. apiRegister(MQTT_TOPIC_COLOR, MQTT_TOPIC_COLOR,
  125. [](char * buffer, size_t len) {
  126. snprintf(buffer, len, "%s", lightColor().c_str());
  127. },
  128. [](const char * payload) {
  129. lightColor(payload, true, mqttForward());
  130. }
  131. );
  132. }
  133. // -----------------------------------------------------------------------------
  134. // SETUP
  135. // -----------------------------------------------------------------------------
  136. void lightSetup() {
  137. #if LIGHT_PROVIDER == LIGHT_PROVIDER_MY9192
  138. _my9291 = new my9291(MY9291_DI_PIN, MY9291_DCKI_PIN, MY9291_COMMAND);
  139. _my9291->setState(true); // We are handling state from the client code
  140. #endif
  141. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_RGB) || (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  142. analogWriteRange(255);
  143. analogWriteFreq(1000);
  144. pinMode(RGBW_RED_PIN, OUTPUT);
  145. pinMode(RGBW_GREEN_PIN, OUTPUT);
  146. pinMode(RGBW_BLUE_PIN, OUTPUT);
  147. #if LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW
  148. pinMode(RGBW_WHITE_PIN, OUTPUT);
  149. #endif
  150. lightColorProvider(0, 0, 0);
  151. #endif
  152. lightColorRetrieve();
  153. mqttRegister(lightMQTTCallback);
  154. lightSetupAPI();
  155. }
  156. #endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE