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.

199 lines
4.5 KiB

  1. /*
  2. ESPurna
  3. RELAY MODULE
  4. Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
  5. */
  6. #include <EEPROM.h>
  7. #include <ArduinoJson.h>
  8. #include <vector>
  9. std::vector<unsigned char> _relays;
  10. bool recursive = false;
  11. #ifdef SONOFF_DUAL
  12. unsigned char dualRelayStatus = 0;
  13. #endif
  14. // -----------------------------------------------------------------------------
  15. // RELAY
  16. // -----------------------------------------------------------------------------
  17. void relayMQTT(unsigned char id) {
  18. char buffer[10];
  19. sprintf(buffer, MQTT_RELAY_TOPIC, id);
  20. mqttSend(buffer, (char *) (relayStatus(id) ? "1" : "0"));
  21. }
  22. void relayMQTT() {
  23. for (unsigned int i=0; i < _relays.size(); i++) {
  24. relayMQTT(i);
  25. }
  26. }
  27. String relayString() {
  28. DynamicJsonBuffer jsonBuffer;
  29. JsonObject& root = jsonBuffer.createObject();
  30. JsonArray& relay = root.createNestedArray("relayStatus");
  31. for (unsigned char i=0; i<relayCount(); i++) {
  32. relay.add(relayStatus(i));
  33. }
  34. String output;
  35. root.printTo(output);
  36. return output;
  37. }
  38. void relayWS() {
  39. String output = relayString();
  40. wsSend((char *) output.c_str());
  41. }
  42. void relaySave() {
  43. unsigned char bit = 1;
  44. unsigned char mask = 0;
  45. for (unsigned int i=0; i < _relays.size(); i++) {
  46. if (relayStatus(i)) mask += bit;
  47. bit += bit;
  48. }
  49. EEPROM.write(0, mask);
  50. EEPROM.commit();
  51. }
  52. void relayRetrieve() {
  53. recursive = true;
  54. unsigned char bit = 1;
  55. unsigned char mask = EEPROM.read(0);
  56. for (unsigned int i=0; i < _relays.size(); i++) {
  57. relayStatus(i, ((mask & bit) == bit));
  58. bit += bit;
  59. }
  60. recursive = false;
  61. }
  62. bool relayStatus(unsigned char id) {
  63. #ifdef SONOFF_DUAL
  64. return ((dualRelayStatus & (1 << id)) > 0);
  65. #else
  66. return (digitalRead(_relays[id]) == HIGH);
  67. #endif
  68. }
  69. void relaySync(unsigned char id) {
  70. if (_relays.size() > 1) {
  71. recursive = true;
  72. byte relaySync = getSetting("relaySync", String(RELAY_SYNC)).toInt();
  73. bool status = relayStatus(id);
  74. // If RELAY_SYNC_SAME all relays should have the same state
  75. if (relaySync == RELAY_SYNC_SAME) {
  76. for (unsigned short i=0; i<_relays.size(); i++) {
  77. if (i != id) relayStatus(i, status);
  78. }
  79. // If NONE_OR_ONE or ONE and setting ON we should set OFF all the others
  80. } else if (status) {
  81. if (relaySync != RELAY_SYNC_ANY) {
  82. for (unsigned short i=0; i<_relays.size(); i++) {
  83. if (i != id) relayStatus(i, false);
  84. }
  85. }
  86. // If ONLY_ONE and setting OFF we should set ON the other one
  87. } else {
  88. if (relaySync == RELAY_SYNC_ONE) {
  89. unsigned char i = (id + 1) % _relays.size();
  90. relayStatus(i, true);
  91. }
  92. }
  93. recursive = false;
  94. }
  95. }
  96. bool relayStatus(unsigned char id, bool status) {
  97. bool changed = false;
  98. if (relayStatus(id) != status) {
  99. DEBUG_MSG("[RELAY] %d => %s\n", id, status ? "ON" : "OFF");
  100. changed = true;
  101. #ifdef SONOFF_DUAL
  102. dualRelayStatus ^= (1 << id);
  103. Serial.flush();
  104. Serial.write(0xA0);
  105. Serial.write(0x04);
  106. Serial.write(dualRelayStatus);
  107. Serial.write(0xA1);
  108. Serial.flush();
  109. #else
  110. digitalWrite(_relays[id], status);
  111. #endif
  112. if (!recursive) {
  113. relaySync(id);
  114. relaySave();
  115. }
  116. }
  117. relayMQTT(id);
  118. if (!recursive) relayWS();
  119. return changed;
  120. }
  121. void relayToggle(unsigned char id) {
  122. relayStatus(id, !relayStatus(id));
  123. }
  124. unsigned char relayCount() {
  125. return _relays.size();
  126. }
  127. void relaySetup() {
  128. #ifdef SONOFF_DUAL
  129. // Two dummy relays for the dual
  130. _relays.push_back(0);
  131. _relays.push_back(0);
  132. #else
  133. #ifdef RELAY1_PIN
  134. _relays.push_back(RELAY1_PIN);
  135. #endif
  136. #ifdef RELAY2_PIN
  137. _relays.push_back(RELAY2_PIN);
  138. #endif
  139. #ifdef RELAY3_PIN
  140. _relays.push_back(RELAY3_PIN);
  141. #endif
  142. #ifdef RELAY4_PIN
  143. _relays.push_back(RELAY4_PIN);
  144. #endif
  145. #endif
  146. EEPROM.begin(4096);
  147. byte relayMode = getSetting("relayMode", String(RELAY_MODE)).toInt();
  148. for (unsigned int i=0; i < _relays.size(); i++) {
  149. pinMode(_relays[i], OUTPUT);
  150. if (relayMode == RELAY_MODE_OFF) relayStatus(i, false);
  151. if (relayMode == RELAY_MODE_ON) relayStatus(i, true);
  152. }
  153. if (relayMode == RELAY_MODE_SAME) relayRetrieve();
  154. }