xdrv_18_armtronix_dimmers.ino 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. xdrv_18_armtronix_dimmers.ino - Armtronix dimmers support for Sonoff-Tasmota
  3. Copyright (C) 2018 wvdv2002 and Theo Arends
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #ifdef USE_ARMTRONIX_DIMMERS
  16. /*********************************************************************************************\
  17. * This code can be used for Armtronix dimmers.
  18. * The dimmers contain a Atmega328 to do the actual dimming.
  19. * Checkout the Tasmota Wiki for information on how to flash this Atmega328 with the firmware
  20. * to work together with this driver.
  21. \*********************************************************************************************/
  22. #define XDRV_18 18
  23. #include <TasmotaSerial.h>
  24. TasmotaSerial *ArmtronixSerial = nullptr;
  25. boolean armtronix_ignore_dim = false; // Flag to skip serial send to prevent looping when processing inbound states from the faceplate interaction
  26. int8_t armtronix_wifi_state = -2; // Keep MCU wifi-status in sync with WifiState()
  27. int8_t armtronix_dimState[2]; // Dimmer state values.
  28. int8_t armtronix_knobState[2]; // Dimmer state values.
  29. /*********************************************************************************************\
  30. * Internal Functions
  31. \*********************************************************************************************/
  32. boolean ArmtronixSetChannels(void)
  33. {
  34. LightSerial2Duty(((uint8_t*)XdrvMailbox.data)[0], ((uint8_t*)XdrvMailbox.data)[1]);
  35. return true;
  36. }
  37. void LightSerial2Duty(uint8_t duty1, uint8_t duty2)
  38. {
  39. if (ArmtronixSerial && !armtronix_ignore_dim) {
  40. duty1 = ((float)duty1)/2.575757; //max 99
  41. duty2 = ((float)duty2)/2.575757; //max 99
  42. armtronix_dimState[0] = duty1;
  43. armtronix_dimState[1] = duty2;
  44. ArmtronixSerial->print("Dimmer1:");
  45. ArmtronixSerial->print(duty1);
  46. ArmtronixSerial->print("\nDimmer2:");
  47. ArmtronixSerial->println(duty2);
  48. snprintf_P(log_data, sizeof(log_data), PSTR( "ARM: Send Serial Packet Dim Values=%d,%d"), armtronix_dimState[0],armtronix_dimState[1]);
  49. AddLog(LOG_LEVEL_DEBUG);
  50. } else {
  51. armtronix_ignore_dim = false;
  52. snprintf_P(log_data, sizeof(log_data), PSTR( "ARM: Send Dim Level skipped due to already set. Value=%d,%d"), armtronix_dimState[0],armtronix_dimState[1]);
  53. AddLog(LOG_LEVEL_DEBUG);
  54. }
  55. }
  56. void ArmtronixRequestState(void)
  57. {
  58. if (ArmtronixSerial) {
  59. // Get current status of MCU
  60. snprintf_P(log_data, sizeof(log_data), "TYA: Request MCU state");
  61. AddLog(LOG_LEVEL_DEBUG);
  62. ArmtronixSerial->println("Status");
  63. }
  64. }
  65. /*********************************************************************************************\
  66. * API Functions
  67. \*********************************************************************************************/
  68. boolean ArmtronixModuleSelected(void)
  69. {
  70. light_type = LT_SERIAL2;
  71. return true;
  72. }
  73. void ArmtronixInit(void)
  74. {
  75. armtronix_dimState[0] = -1;
  76. armtronix_dimState[1] = -1;
  77. armtronix_knobState[0] = -1;
  78. armtronix_knobState[1] = -1;
  79. ArmtronixSerial = new TasmotaSerial(pin[GPIO_RXD], pin[GPIO_TXD], 2);
  80. if (ArmtronixSerial->begin(115200)) {
  81. if (ArmtronixSerial->hardwareSerial()) { ClaimSerial(); }
  82. ArmtronixSerial->println("Status");
  83. }
  84. }
  85. void ArmtronixSerialInput(void)
  86. {
  87. String answer;
  88. int8_t newDimState[2];
  89. uint8_t temp;
  90. int commaIndex;
  91. char scmnd[20];
  92. if (ArmtronixSerial->available()) {
  93. yield();
  94. answer = ArmtronixSerial->readStringUntil('\n');
  95. if (answer.substring(0,7) == "Status:") {
  96. commaIndex = 6;
  97. for (int i =0; i<2; i++) {
  98. newDimState[i] = answer.substring(commaIndex+1,answer.indexOf(',',commaIndex+1)).toInt();
  99. if (newDimState[i] != armtronix_dimState[i]) {
  100. temp = ((float)newDimState[i])*1.01010101010101; //max 255
  101. armtronix_dimState[i] = newDimState[i];
  102. armtronix_ignore_dim = true;
  103. snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_CHANNEL "%d %d"),i+1, temp);
  104. ExecuteCommand(scmnd,SRC_SWITCH);
  105. snprintf_P(log_data, sizeof(log_data), PSTR("ARM: Send CMND_CHANNEL=%s"), scmnd );
  106. AddLog(LOG_LEVEL_DEBUG);
  107. }
  108. commaIndex = answer.indexOf(',',commaIndex+1);
  109. }
  110. armtronix_knobState[0] = answer.substring(commaIndex+1,answer.indexOf(',',commaIndex+1)).toInt();
  111. commaIndex = answer.indexOf(',',commaIndex+1);
  112. armtronix_knobState[1] = answer.substring(commaIndex+1,answer.indexOf(',',commaIndex+1)).toInt();
  113. }
  114. }
  115. }
  116. void ArmtronixSetWifiLed(void)
  117. {
  118. uint8_t wifi_state = 0x02;
  119. switch (WifiState()) {
  120. case WIFI_SMARTCONFIG:
  121. wifi_state = 0x00;
  122. break;
  123. case WIFI_MANAGER:
  124. case WIFI_WPSCONFIG:
  125. wifi_state = 0x01;
  126. break;
  127. case WIFI_RESTART:
  128. wifi_state = 0x03;
  129. break;
  130. }
  131. snprintf_P(log_data, sizeof(log_data), "ARM: Set WiFi LED to state %d (%d)", wifi_state, WifiState());
  132. AddLog(LOG_LEVEL_DEBUG);
  133. char state = '0' + (wifi_state & 1 > 0);
  134. ArmtronixSerial->print("Setled:");
  135. ArmtronixSerial->write(state);
  136. ArmtronixSerial->write(',');
  137. state = '0' + (wifi_state & 2 > 0);
  138. ArmtronixSerial->write(state);
  139. ArmtronixSerial->write(10);
  140. armtronix_wifi_state = WifiState();
  141. }
  142. /*********************************************************************************************\
  143. * Interface
  144. \*********************************************************************************************/
  145. boolean Xdrv18(byte function)
  146. {
  147. boolean result = false;
  148. if (ARMTRONIX_DIMMERS == Settings.module) {
  149. switch (function) {
  150. case FUNC_MODULE_INIT:
  151. result = ArmtronixModuleSelected();
  152. break;
  153. case FUNC_INIT:
  154. ArmtronixInit();
  155. break;
  156. case FUNC_LOOP:
  157. if (ArmtronixSerial) { ArmtronixSerialInput(); }
  158. break;
  159. case FUNC_EVERY_SECOND:
  160. if (ArmtronixSerial) {
  161. if (armtronix_wifi_state!=WifiState()) { ArmtronixSetWifiLed(); }
  162. if (uptime &1) {
  163. ArmtronixSerial->println("Status");
  164. }
  165. }
  166. break;
  167. case FUNC_SET_CHANNELS:
  168. result = ArmtronixSetChannels();
  169. break;
  170. }
  171. }
  172. return result;
  173. }
  174. #endif // USE_ARMTRONIX_DIMMERS