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.

200 lines
5.5 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 _lightProviderSet(bool state, unsigned int red, unsigned int green, unsigned int blue) {
  35. unsigned int white = 0;
  36. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_MY9192) || (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  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->setState(state);
  45. _my9291->setColor((my9291_color_t) { red, green, blue, white });
  46. #endif
  47. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_RGB) || (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  48. // Check state
  49. if (!state) red = green = blue = white = 0;
  50. if (RGBW_INVERSE_LOGIC) {
  51. analogWrite(RGBW_RED_PIN, red);
  52. analogWrite(RGBW_GREEN_PIN, green);
  53. analogWrite(RGBW_BLUE_PIN, blue);
  54. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  55. analogWrite(RGBW_WHITE_PIN, white);
  56. #endif
  57. } else {
  58. analogWrite(RGBW_RED_PIN, 255 - red);
  59. analogWrite(RGBW_GREEN_PIN, 255 - green);
  60. analogWrite(RGBW_BLUE_PIN, 255 - blue);
  61. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  62. analogWrite(RGBW_WHITE_PIN, 255 - white);
  63. #endif
  64. }
  65. #endif
  66. }
  67. // -----------------------------------------------------------------------------
  68. // LIGHT MANAGEMENT
  69. // -----------------------------------------------------------------------------
  70. void lightState(bool state) {
  71. _lightState = state;
  72. _lightProviderSet(_lightState, _lightColor[0], _lightColor[1], _lightColor[2]);
  73. }
  74. bool lightState() {
  75. return _lightState;
  76. }
  77. void lightColor(const char * rgb, bool save, bool forward) {
  78. color_rgb2array(rgb, _lightColor);
  79. _lightProviderSet(_lightState, _lightColor[0], _lightColor[1], _lightColor[2]);
  80. // Delay saving to EEPROM 5 seconds to avoid wearing it out unnecessarily
  81. if (save) colorTicker.once(LIGHT_SAVE_DELAY, _lightColorSave);
  82. // Report color to MQTT broker
  83. if (forward) mqttSend(MQTT_TOPIC_COLOR, rgb);
  84. // Report color to WS clients
  85. char message[20];
  86. sprintf(message, "{\"color\": \"%s\"}", rgb);
  87. wsSend(message);
  88. }
  89. String lightColor() {
  90. char rgb[8];
  91. color_array2rgb(_lightColor, rgb);
  92. return String(rgb);
  93. }
  94. // -----------------------------------------------------------------------------
  95. // PERSISTANCE
  96. // -----------------------------------------------------------------------------
  97. void _lightColorSave() {
  98. setSetting("color", lightColor());
  99. saveSettings();
  100. }
  101. void _lightColorRestore() {
  102. String color = getSetting("color", LIGHT_DEFAULT_COLOR);
  103. lightColor(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. // SETUP
  121. // -----------------------------------------------------------------------------
  122. void lightSetup() {
  123. #if LIGHT_PROVIDER == LIGHT_PROVIDER_MY9192
  124. _my9291 = new my9291(MY9291_DI_PIN, MY9291_DCKI_PIN, MY9291_COMMAND);
  125. #endif
  126. #if (LIGHT_PROVIDER == LIGHT_PROVIDER_RGB) || (LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW)
  127. analogWriteRange(255);
  128. analogWriteFreq(1000);
  129. pinMode(RGBW_RED_PIN, OUTPUT);
  130. pinMode(RGBW_GREEN_PIN, OUTPUT);
  131. pinMode(RGBW_BLUE_PIN, OUTPUT);
  132. #if LIGHT_PROVIDER == LIGHT_PROVIDER_RGBW
  133. pinMode(RGBW_WHITE_PIN, OUTPUT);
  134. #endif
  135. #endif
  136. _lightColorRestore();
  137. // API entry points (protected with apikey)
  138. apiRegister(MQTT_TOPIC_COLOR, MQTT_TOPIC_COLOR,
  139. [](char * buffer, size_t len) {
  140. snprintf(buffer, len, "%s", lightColor().c_str());
  141. },
  142. [](const char * payload) {
  143. lightColor(payload, true, mqttForward());
  144. }
  145. );
  146. mqttRegister(lightMQTTCallback);
  147. }
  148. #endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE