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.

339 lines
9.2 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. /*
  2. LED MODULE
  3. Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. // -----------------------------------------------------------------------------
  6. // LED
  7. // -----------------------------------------------------------------------------
  8. #if LED_SUPPORT
  9. typedef struct {
  10. unsigned char pin;
  11. bool reverse;
  12. unsigned char mode;
  13. unsigned char relay;
  14. } led_t;
  15. std::vector<led_t> _leds;
  16. bool _led_update = false; // For relay-based modes
  17. // -----------------------------------------------------------------------------
  18. bool _ledStatus(unsigned char id) {
  19. if (id >= _ledCount()) return false;
  20. bool status = digitalRead(_leds[id].pin);
  21. return _leds[id].reverse ? !status : status;
  22. }
  23. bool _ledStatus(unsigned char id, bool status) {
  24. if (id >=_ledCount()) return false;
  25. digitalWrite(_leds[id].pin, _leds[id].reverse ? !status : status);
  26. return status;
  27. }
  28. bool _ledToggle(unsigned char id) {
  29. if (id >= _ledCount()) return false;
  30. return _ledStatus(id, !_ledStatus(id));
  31. }
  32. unsigned char _ledMode(unsigned char id) {
  33. if (id >= _ledCount()) return false;
  34. return _leds[id].mode;
  35. }
  36. void _ledMode(unsigned char id, unsigned char mode) {
  37. if (id >= _ledCount()) return;
  38. _leds[id].mode = mode;
  39. }
  40. unsigned char _ledRelay(unsigned char id) {
  41. if (id >= _ledCount()) return false;
  42. return _leds[id].relay;
  43. }
  44. void _ledRelay(unsigned char id, unsigned char relay) {
  45. if (id >= _ledCount()) return;
  46. _leds[id].relay = relay;
  47. }
  48. void _ledBlink(unsigned char id, unsigned long delayOff, unsigned long delayOn) {
  49. if (id >= _ledCount()) return;
  50. static unsigned long next = millis();
  51. if (next < millis()) {
  52. next += (_ledToggle(id) ? delayOn : delayOff);
  53. }
  54. }
  55. #if WEB_SUPPORT
  56. bool _ledWebSocketOnKeyCheck(const char * key, JsonVariant& value) {
  57. return (strncmp(key, "led", 3) == 0);
  58. }
  59. void _ledWebSocketOnVisible(JsonObject& root) {
  60. if (_ledCount() > 0) {
  61. root["ledVisible"] = 1;
  62. }
  63. }
  64. void _ledWebSocketOnConnected(JsonObject& root) {
  65. if (_ledCount() == 0) return;
  66. JsonArray& leds = root.createNestedArray("ledConfig");
  67. for (byte i=0; i<_ledCount(); i++) {
  68. JsonObject& led = leds.createNestedObject();
  69. led["mode"] = getSetting("ledMode", i, "").toInt();
  70. led["relay"] = getSetting("ledRelay", i, "").toInt();
  71. }
  72. }
  73. #endif
  74. #if BROKER_SUPPORT
  75. void _ledBrokerCallback(const unsigned char type, const char * topic, unsigned char id, const char * payload) {
  76. // Only process status messages
  77. if (BROKER_MSG_TYPE_STATUS != type) return;
  78. if (strcmp(MQTT_TOPIC_RELAY, topic) == 0) {
  79. ledUpdate(true);
  80. }
  81. }
  82. #endif // BROKER_SUPPORT
  83. #if MQTT_SUPPORT
  84. void _ledMQTTCallback(unsigned int type, const char * topic, const char * payload) {
  85. if (type == MQTT_CONNECT_EVENT) {
  86. char buffer[strlen(MQTT_TOPIC_LED) + 3];
  87. snprintf_P(buffer, sizeof(buffer), PSTR("%s/+"), MQTT_TOPIC_LED);
  88. mqttSubscribe(buffer);
  89. }
  90. if (type == MQTT_MESSAGE_EVENT) {
  91. // Match topic
  92. String t = mqttMagnitude((char *) topic);
  93. if (!t.startsWith(MQTT_TOPIC_LED)) return;
  94. // Get led ID
  95. unsigned int ledID = t.substring(strlen(MQTT_TOPIC_LED)+1).toInt();
  96. if (ledID >= _ledCount()) {
  97. DEBUG_MSG_P(PSTR("[LED] Wrong ledID (%d)\n"), ledID);
  98. return;
  99. }
  100. // Check if LED is managed
  101. if (_ledMode(ledID) != LED_MODE_MQTT) return;
  102. // get value
  103. const auto value = relayParsePayload(payload);
  104. // Action to perform
  105. if (value == RelayStatus::TOGGLE) {
  106. _ledToggle(ledID);
  107. } else {
  108. _ledStatus(ledID, (value == RelayStatus::ON));
  109. }
  110. }
  111. }
  112. #endif
  113. unsigned char _ledCount() {
  114. return _leds.size();
  115. }
  116. void _ledConfigure() {
  117. for (unsigned int i=0; i < _leds.size(); i++) {
  118. _ledMode(i, getSetting("ledMode", i, _ledMode(i)).toInt());
  119. _ledRelay(i, getSetting("ledRelay", i, _ledRelay(i)).toInt());
  120. }
  121. _led_update = true;
  122. }
  123. // -----------------------------------------------------------------------------
  124. void ledUpdate(bool value) {
  125. _led_update = value;
  126. }
  127. void ledSetup() {
  128. #if LED1_PIN != GPIO_NONE
  129. _leds.push_back((led_t) { LED1_PIN, LED1_PIN_INVERSE, LED1_MODE, LED1_RELAY - 1 });
  130. #endif
  131. #if LED2_PIN != GPIO_NONE
  132. _leds.push_back((led_t) { LED2_PIN, LED2_PIN_INVERSE, LED2_MODE, LED2_RELAY - 1 });
  133. #endif
  134. #if LED3_PIN != GPIO_NONE
  135. _leds.push_back((led_t) { LED3_PIN, LED3_PIN_INVERSE, LED3_MODE, LED3_RELAY - 1 });
  136. #endif
  137. #if LED4_PIN != GPIO_NONE
  138. _leds.push_back((led_t) { LED4_PIN, LED4_PIN_INVERSE, LED4_MODE, LED4_RELAY - 1 });
  139. #endif
  140. #if LED5_PIN != GPIO_NONE
  141. _leds.push_back((led_t) { LED5_PIN, LED5_PIN_INVERSE, LED5_MODE, LED5_RELAY - 1 });
  142. #endif
  143. #if LED6_PIN != GPIO_NONE
  144. _leds.push_back((led_t) { LED6_PIN, LED6_PIN_INVERSE, LED6_MODE, LED6_RELAY - 1 });
  145. #endif
  146. #if LED7_PIN != GPIO_NONE
  147. _leds.push_back((led_t) { LED7_PIN, LED7_PIN_INVERSE, LED7_MODE, LED7_RELAY - 1 });
  148. #endif
  149. #if LED8_PIN != GPIO_NONE
  150. _leds.push_back((led_t) { LED8_PIN, LED8_PIN_INVERSE, LED8_MODE, LED8_RELAY - 1 });
  151. #endif
  152. for (unsigned int i=0; i < _leds.size(); i++) {
  153. if (!hasSetting("ledMode", i)) setSetting("ledMode", i, _leds[i].mode);
  154. if (!hasSetting("ledRelay", i)) setSetting("ledRelay", i, _leds[i].relay);
  155. pinMode(_leds[i].pin, OUTPUT);
  156. _ledStatus(i, false);
  157. }
  158. _ledConfigure();
  159. #if MQTT_SUPPORT
  160. mqttRegister(_ledMQTTCallback);
  161. #endif
  162. #if WEB_SUPPORT
  163. wsRegister()
  164. .onVisible(_ledWebSocketOnVisible)
  165. .onConnected(_ledWebSocketOnConnected)
  166. .onKeyCheck(_ledWebSocketOnKeyCheck);
  167. #endif
  168. #if BROKER_SUPPORT
  169. brokerRegister(_ledBrokerCallback);
  170. #endif
  171. DEBUG_MSG_P(PSTR("[LED] Number of leds: %d\n"), _leds.size());
  172. // Main callbacks
  173. espurnaRegisterLoop(ledLoop);
  174. espurnaRegisterReload(_ledConfigure);
  175. }
  176. void ledLoop() {
  177. uint8_t wifi_state = wifiState();
  178. for (unsigned char i=0; i<_leds.size(); i++) {
  179. if (_ledMode(i) == LED_MODE_WIFI) {
  180. if (wifi_state & WIFI_STATE_WPS || wifi_state & WIFI_STATE_SMARTCONFIG) {
  181. _ledBlink(i, 100, 100);
  182. } else if (wifi_state & WIFI_STATE_STA) {
  183. _ledBlink(i, 4900, 100);
  184. } else if (wifi_state & WIFI_STATE_AP) {
  185. _ledBlink(i, 900, 100);
  186. } else {
  187. _ledBlink(i, 500, 500);
  188. }
  189. }
  190. if (_ledMode(i) == LED_MODE_FINDME_WIFI) {
  191. if (wifi_state & WIFI_STATE_WPS || wifi_state & WIFI_STATE_SMARTCONFIG) {
  192. _ledBlink(i, 100, 100);
  193. } else if (wifi_state & WIFI_STATE_STA) {
  194. if (relayStatus(_leds[i].relay)) {
  195. _ledBlink(i, 4900, 100);
  196. } else {
  197. _ledBlink(i, 100, 4900);
  198. }
  199. } else if (wifi_state & WIFI_STATE_AP) {
  200. if (relayStatus(_leds[i].relay)) {
  201. _ledBlink(i, 900, 100);
  202. } else {
  203. _ledBlink(i, 100, 900);
  204. }
  205. } else {
  206. _ledBlink(i, 500, 500);
  207. }
  208. }
  209. if (_ledMode(i) == LED_MODE_RELAY_WIFI) {
  210. if (wifi_state & WIFI_STATE_WPS || wifi_state & WIFI_STATE_SMARTCONFIG) {
  211. _ledBlink(i, 100, 100);
  212. } else if (wifi_state & WIFI_STATE_STA) {
  213. if (relayStatus(_leds[i].relay)) {
  214. _ledBlink(i, 100, 4900);
  215. } else {
  216. _ledBlink(i, 4900, 100);
  217. }
  218. } else if (wifi_state & WIFI_STATE_AP) {
  219. if (relayStatus(_leds[i].relay)) {
  220. _ledBlink(i, 100, 900);
  221. } else {
  222. _ledBlink(i, 900, 100);
  223. }
  224. } else {
  225. _ledBlink(i, 500, 500);
  226. }
  227. }
  228. // Relay-based modes, update only if relays have been updated
  229. if (!_led_update) continue;
  230. if (_ledMode(i) == LED_MODE_FOLLOW) {
  231. _ledStatus(i, relayStatus(_leds[i].relay));
  232. }
  233. if (_ledMode(i) == LED_MODE_FOLLOW_INVERSE) {
  234. _ledStatus(i, !relayStatus(_leds[i].relay));
  235. }
  236. if (_ledMode(i) == LED_MODE_FINDME) {
  237. bool status = true;
  238. for (unsigned char k=0; k<relayCount(); k++) {
  239. if (relayStatus(k)) {
  240. status = false;
  241. break;
  242. }
  243. }
  244. _ledStatus(i, status);
  245. }
  246. if (_ledMode(i) == LED_MODE_RELAY) {
  247. bool status = false;
  248. for (unsigned char k=0; k<relayCount(); k++) {
  249. if (relayStatus(k)) {
  250. status = true;
  251. break;
  252. }
  253. }
  254. _ledStatus(i, status);
  255. }
  256. if (_ledMode(i) == LED_MODE_ON) {
  257. _ledStatus(i, true);
  258. }
  259. if (_ledMode(i) == LED_MODE_OFF) {
  260. _ledStatus(i, false);
  261. }
  262. }
  263. _led_update = false;
  264. }
  265. #endif // LED_SUPPORT