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.

232 lines
6.3 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_string2array(const char * rgb, unsigned int * array) {
  18. char * p = (char *) rgb;
  19. if (strlen(p) == 0) return;
  20. // if color begins with a # then assume HEX RGB
  21. if (p[0] == '#') {
  22. ++p;
  23. unsigned long value = strtol(p, NULL, 16);
  24. array[0] = (value >> 16) & 0xFF;
  25. array[1] = (value >> 8) & 0xFF;
  26. array[2] = (value) & 0xFF;
  27. // otherwise assume decimal values separated by commas
  28. } else {
  29. char * tok;
  30. tok = strtok(p, ",");
  31. array[0] = atoi(tok);
  32. tok = strtok(NULL, ",");
  33. // if there are more than one value assume R,G,B
  34. if (tok != NULL) {
  35. array[1] = atoi(tok);
  36. tok = strtok(NULL, ",");
  37. if (tok != NULL) {
  38. array[2] = atoi(tok);
  39. } else {
  40. array[2] = 0;
  41. }
  42. // only one value set red, green and blue to the same value
  43. } else {
  44. array[2] = array[1] = array[0];
  45. }
  46. }
  47. }
  48. void color_array2string(unsigned int * array, char * rgb) {
  49. unsigned long value = array[0];
  50. value = (value << 8) + array[1];
  51. value = (value << 8) + array[2];
  52. sprintf(rgb, "#%06X", value);
  53. }
  54. // -----------------------------------------------------------------------------
  55. // PROVIDER
  56. // -----------------------------------------------------------------------------
  57. void _lightProviderSet(bool state, unsigned int red, unsigned int green, unsigned int blue) {
  58. unsigned int white = 0;
  59. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_MY9192) || (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  60. // If all set to the same value use white instead
  61. if ((red == green) && (green == blue)) {
  62. white = red;
  63. red = green = blue = 0;
  64. }
  65. #endif
  66. #if LIGHT_PROVIDER == LIGHT_PROVIDER_MY9192
  67. _my9291->setState(state);
  68. _my9291->setColor((my9291_color_t) { red, green, blue, white });
  69. #endif
  70. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_RGB) || (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  71. // Check state
  72. if (!state) red = green = blue = white = 0;
  73. if (RGBW_INVERSE_LOGIC) {
  74. analogWrite(RGBW_RED_PIN, red);
  75. analogWrite(RGBW_GREEN_PIN, green);
  76. analogWrite(RGBW_BLUE_PIN, blue);
  77. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  78. analogWrite(RGBW_WHITE_PIN, white);
  79. #endif
  80. } else {
  81. analogWrite(RGBW_RED_PIN, 255 - red);
  82. analogWrite(RGBW_GREEN_PIN, 255 - green);
  83. analogWrite(RGBW_BLUE_PIN, 255 - blue);
  84. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  85. analogWrite(RGBW_WHITE_PIN, 255 - white);
  86. #endif
  87. }
  88. #endif
  89. }
  90. // -----------------------------------------------------------------------------
  91. // LIGHT MANAGEMENT
  92. // -----------------------------------------------------------------------------
  93. void lightState(bool state) {
  94. _lightState = state;
  95. _lightProviderSet(_lightState, _lightColor[0], _lightColor[1], _lightColor[2]);
  96. }
  97. bool lightState() {
  98. return _lightState;
  99. }
  100. void lightColor(const char * rgb, bool save, bool forward) {
  101. color_string2array(rgb, _lightColor);
  102. _lightProviderSet(_lightState, _lightColor[0], _lightColor[1], _lightColor[2]);
  103. char color[12];
  104. color_array2string(_lightColor, color);
  105. // Delay saving to EEPROM 5 seconds to avoid wearing it out unnecessarily
  106. if (save) colorTicker.once(LIGHT_SAVE_DELAY, _lightColorSave);
  107. // Report color to MQTT broker
  108. if (forward) mqttSend(MQTT_TOPIC_COLOR, color);
  109. // Report color to WS clients
  110. char message[20];
  111. sprintf(message, "{\"color\": \"%s\"}", color);
  112. wsSend(message);
  113. }
  114. String lightColor() {
  115. char rgb[8];
  116. color_array2string(_lightColor, rgb);
  117. return String(rgb);
  118. }
  119. // -----------------------------------------------------------------------------
  120. // PERSISTANCE
  121. // -----------------------------------------------------------------------------
  122. void _lightColorSave() {
  123. setSetting("color", lightColor());
  124. saveSettings();
  125. }
  126. void _lightColorRestore() {
  127. String color = getSetting("color", LIGHT_DEFAULT_COLOR);
  128. lightColor(color.c_str(), false, true);
  129. }
  130. // -----------------------------------------------------------------------------
  131. // MQTT
  132. // -----------------------------------------------------------------------------
  133. void lightMQTTCallback(unsigned int type, const char * topic, const char * payload) {
  134. if (type == MQTT_CONNECT_EVENT) {
  135. mqttSubscribe(MQTT_TOPIC_COLOR);
  136. }
  137. if (type == MQTT_MESSAGE_EVENT) {
  138. // Match topic
  139. String t = mqttSubtopic((char *) topic);
  140. if (!t.equals(MQTT_TOPIC_COLOR)) return;
  141. lightColor(payload, true, mqttForward());
  142. }
  143. }
  144. // -----------------------------------------------------------------------------
  145. // SETUP
  146. // -----------------------------------------------------------------------------
  147. void lightSetup() {
  148. #if LIGHT_PROVIDER == LIGHT_PROVIDER_MY9192
  149. _my9291 = new my9291(MY9291_DI_PIN, MY9291_DCKI_PIN, MY9291_COMMAND);
  150. #endif
  151. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_RGB) || (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  152. analogWriteRange(255);
  153. analogWriteFreq(1000);
  154. pinMode(RGBW_RED_PIN, OUTPUT);
  155. pinMode(RGBW_GREEN_PIN, OUTPUT);
  156. pinMode(RGBW_BLUE_PIN, OUTPUT);
  157. #if LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW
  158. pinMode(RGBW_WHITE_PIN, OUTPUT);
  159. #endif
  160. #endif
  161. _lightColorRestore();
  162. // API entry points (protected with apikey)
  163. apiRegister(MQTT_TOPIC_COLOR, MQTT_TOPIC_COLOR,
  164. [](char * buffer, size_t len) {
  165. snprintf(buffer, len, "%s", lightColor().c_str());
  166. },
  167. [](const char * payload) {
  168. lightColor(payload, true, mqttForward());
  169. }
  170. );
  171. mqttRegister(lightMQTTCallback);
  172. }
  173. #endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE