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.

431 lines
14 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. /*
  2. IR MODULE
  3. Copyright (C) 2018 by Alexander Kolesnikov (raw and MQTT implementation)
  4. Copyright (C) 2017-2018 by François Déchery
  5. Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
  6. -----------------------------------------------------------------------------
  7. Configuration
  8. -----------------------------------------------------------------------------
  9. To enable transmit functions define IR_TX_PIN
  10. To enable receiver functions define IR_RX_PIN
  11. MQTT input topic: {root}/irin
  12. MQTT output topic: {root}/irout/set
  13. --------------------------------------------------------------------------------
  14. MQTT messages
  15. --------------------------------------------------------------------------------
  16. Decoded messages:
  17. Transmitting:
  18. Payload: 2:121944:32:1 (<type>:<code>:<bits>[:<repeat>])
  19. The repeat value is optional and defaults to 1
  20. Receiving:
  21. Payload: 2:121944:32 (<type>:<code>:<bits>)
  22. Raw messages:
  23. Transmitting:
  24. Payload: 1000,1000,1000,1000,1000,DELAY,COUNT,FREQ:500,500,500,500,500
  25. | IR codes | | IR repeat codes |
  26. codes - time in microseconds when IR LED On/Off. First value - ON, second - Off ...
  27. DELAY - delay in milliseconds between sending repeats
  28. COUNT - how many repeats send. Max 120.
  29. FREQ - modulation frequency. Usually 38kHz. You may set 38, it means 38kHz or set 38000, it meant same.
  30. Repeat codes is optional. You may omit ":" and codes. In this case if repeat count > 0 we repeat main code.
  31. Receiving:
  32. Payload: 1000,1000,1000,1000,1000
  33. | IR codes |
  34. * To support long codes (Air Conditioneer) increase MQTT packet size -DMQTT_MAX_PACKET_SIZE=1200
  35. --------------------------------------------------------------------------------
  36. */
  37. #if IR_SUPPORT
  38. #include <IRremoteESP8266.h>
  39. #if defined(IR_RX_PIN)
  40. #include <IRrecv.h>
  41. IRrecv _ir_receiver(IR_RX_PIN, IR_BUFFER_SIZE, IR_TIMEOUT, true);
  42. decode_results _ir_results;
  43. #endif // defined(IR_RX_PIN)
  44. #if defined(IR_TX_PIN)
  45. #include <IRsend.h>
  46. IRsend _ir_sender(IR_TX_PIN);
  47. #if IR_USE_RAW
  48. uint16_t _ir_freq = 38; // IR modulation freq. for sending codes and repeat codes
  49. uint8_t _ir_repeat_size = 0; // size of repeat array
  50. uint16_t * _ir_raw; // array for sending codes and repeat codes
  51. #else
  52. uint8_t _ir_type = 0; // Type of encoding
  53. uint64_t _ir_code = 0; // Code to transmit
  54. uint16_t _ir_bits = 0; // Code bits
  55. #endif
  56. uint8_t _ir_repeat = 0; // count of times repeating of repeat_code
  57. uint32_t _ir_delay = IR_DELAY; // delay between repeat codes
  58. #endif // defined(IR_TX_PIN)
  59. // MQTT to IR
  60. #if MQTT_SUPPORT && defined(IR_TX_PIN)
  61. void _irMqttCallback(unsigned int type, const char * topic, const char * payload) {
  62. if (type == MQTT_CONNECT_EVENT) {
  63. mqttSubscribe(MQTT_TOPIC_IROUT);
  64. }
  65. if (type == MQTT_MESSAGE_EVENT) {
  66. String t = mqttMagnitude((char *) topic);
  67. // Match topic
  68. if (t.equals(MQTT_TOPIC_IROUT)) {
  69. String data = String(payload);
  70. unsigned int len = data.length();
  71. int col = data.indexOf(":"); // position of ":" which means repeat_code
  72. #if IR_USE_RAW
  73. unsigned char count = 1; // count of code values for allocating array
  74. if (col > 2) { // count & validating repeat code
  75. _ir_repeat_size = 1;
  76. // count & validate repeat-string
  77. for(int i = col+1; i < len; i++) {
  78. if (i < len-1) {
  79. if ( payload[i] == ',' && isDigit(payload[i+1]) && i>0 ) { //validate string
  80. _ir_repeat_size++;
  81. } else if (!isDigit(payload[i])) {
  82. // Error in repeat_code. Use comma separated unsigned integer values.
  83. // Last three is repeat delay, repeat count(<120) and frequency.
  84. // After all you may write ':' and specify repeat code followed by comma.
  85. DEBUG_MSG_P(PSTR("[IR] Error in repeat code.\n"));
  86. return;
  87. }
  88. }
  89. }
  90. len = col; //cut repeat code from main code processing
  91. } // end of counting & validating repeat code
  92. // count & validate main code string
  93. for(int i = 0; i < len; i++) {
  94. if (i<len-1) {
  95. if ( payload[i] == ',' && isDigit(payload[i+1]) && i>0 ) { //validate string
  96. count++;
  97. } else if (!isDigit(payload[i])) {
  98. // Error in main code. Use comma separated unsigned integer values.
  99. // Last three is repeat delay, repeat count(<120) and frequency.
  100. // After all you may write ':' and specify repeat code followed by comma.
  101. DEBUG_MSG_P(PSTR("[IR] Error in main code.\n"));
  102. return;
  103. }
  104. }
  105. }
  106. _ir_raw = (uint16_t*)calloc(count, sizeof(uint16_t)); // allocating array for main codes
  107. String value = ""; // for populating values of array from comma separated string
  108. int j = 0; // for populating values of array from comma separated string
  109. // populating main code array from part of MQTT string
  110. for (int i = 0; i < len; i++) {
  111. if (payload[i] != ',') {
  112. value = value + data[i];
  113. }
  114. if ((payload[i] == ',') || (i == len - 1)) {
  115. _ir_raw[j]= value.toInt();
  116. value = "";
  117. j++;
  118. }
  119. }
  120. // if count>3 then we have values, repeat delay, count and modulation frequency
  121. _ir_repeat=0;
  122. if (count>3) {
  123. if (_ir_raw[count-2] <= 120) { // if repeat count > 120 it's to long and ussualy unusual. maybe we get raw code without this parameters and just use defaults for freq.
  124. _ir_freq = _ir_raw[count-1];
  125. _ir_repeat = _ir_raw[count-2];
  126. _ir_delay = _ir_raw[count-3];
  127. count = count - 3;
  128. }
  129. }
  130. DEBUG_MSG_P(PSTR("[IR] Raw IR output %d codes, repeat %d times on %d(k)Hz freq.\n"), count, _ir_repeat, _ir_freq);
  131. /*
  132. DEBUG_MSG("[IR] main codes: ");
  133. for(int i = 0; i < count; i++) {
  134. DEBUG_MSG("%d,",_ir_raw[i]);
  135. }
  136. DEBUG_MSG("\n");
  137. */
  138. #if defined(IR_RX_PIN)
  139. _ir_receiver.disableIRIn();
  140. #endif
  141. _ir_sender.sendRaw(_ir_raw, count, _ir_freq);
  142. if (_ir_repeat==0) { // no repeat, cleaning array, enabling receiver
  143. free(_ir_raw);
  144. #if defined(IR_RX_PIN)
  145. _ir_receiver.enableIRIn();
  146. #endif
  147. } else if (col>2) { // repeat with repeat_code
  148. DEBUG_MSG_P(PSTR("[IR] Repeat codes count: %d\n"), _ir_repeat_size);
  149. free(_ir_raw);
  150. _ir_raw = (uint16_t*)calloc(_ir_repeat_size, sizeof(uint16_t));
  151. String value = ""; // for populating values of array from comma separated string
  152. int j = 0; // for populating values of array from comma separated string
  153. len = data.length(); //redifining length to full lenght
  154. // populating repeat code array from part of MQTT string
  155. for (int i = col+1; i < len; i++) {
  156. value = value + data[i];
  157. if ((payload[i] == ',') || (i == len - 1)) {
  158. _ir_raw[j]= value.toInt();
  159. value = "";
  160. j++;
  161. }
  162. }
  163. } else { // if repeat code not specified (col<=2) repeat with current main code
  164. _ir_repeat_size = count;
  165. }
  166. #else
  167. _ir_repeat = 0;
  168. if (col > 0) {
  169. _ir_type = data.toInt();
  170. _ir_code = data.substring(col+1).toInt();
  171. col = data.indexOf(":", col+1);
  172. if (col > 0) {
  173. _ir_bits = data.substring(col+1).toInt();
  174. col = data.indexOf(":", col+1);
  175. if (col > 2) {
  176. _ir_repeat = data.substring(col+1).toInt();
  177. } else {
  178. _ir_repeat = IR_REPEAT;
  179. }
  180. }
  181. }
  182. if (_ir_repeat > 0) {
  183. DEBUG_MSG_P(PSTR("[IR] IROUT: %d:%lu:%d:%d\n"), _ir_type, (unsigned long) _ir_code, _ir_bits, _ir_repeat);
  184. } else {
  185. DEBUG_MSG_P(PSTR("[IR] Wrong MQTT payload format (%s)\n"), payload);
  186. }
  187. #endif // IR_USE_RAW
  188. } // end of match topic
  189. } // end of MQTT message
  190. } //end of function
  191. void _irTXLoop() {
  192. static uint32_t last = 0;
  193. if ((_ir_repeat > 0) && (millis() - last > _ir_delay)) {
  194. last = millis();
  195. // Send message
  196. #if IR_USE_RAW
  197. _ir_sender.sendRaw(_ir_raw, _ir_repeat_size, _ir_freq);
  198. #else
  199. _ir_sender.send(_ir_type, _ir_code, _ir_bits);
  200. #endif
  201. // Update repeat count
  202. --_ir_repeat;
  203. if (0 == _ir_repeat) {
  204. #if IR_USE_RAW
  205. free(_ir_raw);
  206. #endif
  207. #if defined(IR_RX_PIN)
  208. _ir_receiver.enableIRIn();
  209. #endif
  210. }
  211. }
  212. }
  213. #endif // MQTT_SUPPORT && defined(IR_TX_PIN)
  214. // Receiving
  215. #if defined(IR_RX_PIN)
  216. void _irProcess(unsigned char type, unsigned long code) {
  217. #if IR_BUTTON_SET > 0
  218. boolean found = false;
  219. for (unsigned char i = 0; i < IR_BUTTON_COUNT ; i++) {
  220. uint32_t button_code = pgm_read_dword(&IR_BUTTON[i][0]);
  221. if (code == button_code) {
  222. unsigned long button_mode = pgm_read_dword(&IR_BUTTON[i][1]);
  223. unsigned long button_value = pgm_read_dword(&IR_BUTTON[i][2]);
  224. if (button_mode == IR_BUTTON_MODE_STATE) {
  225. relayStatus(0, button_value);
  226. }
  227. if (button_mode == IR_BUTTON_MODE_TOGGLE) {
  228. relayToggle(button_value);
  229. }
  230. #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
  231. if (button_mode == IR_BUTTON_MODE_BRIGHTER) {
  232. lightBrightnessStep(button_value ? 1 : -1);
  233. nice_delay(150); //debounce
  234. }
  235. if (button_mode == IR_BUTTON_MODE_RGB) {
  236. lightColor(button_value);
  237. }
  238. /*
  239. #if LIGHT_PROVIDER == LIGHT_PROVIDER_FASTLED
  240. if (button_mode == IR_BUTTON_MODE_EFFECT) {
  241. _buttonAnimMode(button_value);
  242. }
  243. #endif
  244. */
  245. /*
  246. if (button_mode == IR_BUTTON_MODE_HSV) {
  247. lightColor(button_value);
  248. }
  249. */
  250. lightUpdate(true, true);
  251. #endif
  252. found = true;
  253. break;
  254. }
  255. }
  256. if (!found) {
  257. DEBUG_MSG_P(PSTR("[IR] Code does not match any action\n"));
  258. }
  259. #endif
  260. }
  261. void _irRXLoop() {
  262. if (_ir_receiver.decode(&_ir_results)) {
  263. _ir_receiver.resume(); // Receive the next value
  264. // Debounce
  265. static unsigned long last_time = 0;
  266. if (millis() - last_time < IR_DEBOUNCE) return;
  267. last_time = millis();
  268. // Check code
  269. if (_ir_results.value < 1) return;
  270. if (_ir_results.decode_type < 1) return;
  271. if (_ir_results.bits < 1) return;
  272. #if IR_USE_RAW
  273. char * payload;
  274. String value = "";
  275. for (int i = 1; i < _ir_results.rawlen; i++) {
  276. if (i>1) value = value + ",";
  277. value = value + String(_ir_results.rawbuf[i] * RAWTICK);
  278. }
  279. payload = const_cast<char*>(value.c_str());
  280. #else
  281. char payload[32];
  282. snprintf_P(payload, sizeof(payload), PSTR("%u:%lu:%u"), _ir_results.decode_type, (unsigned long) _ir_results.value, _ir_results.bits);
  283. #endif
  284. DEBUG_MSG_P(PSTR("[IR] IRIN: %s\n"), payload);
  285. #if not IR_USE_RAW
  286. _irProcess(_ir_results.decode_type, (unsigned long) _ir_results.value);
  287. #endif
  288. #if MQTT_SUPPORT
  289. if (strlen(payload)>0) {
  290. mqttSend(MQTT_TOPIC_IRIN, (const char *) payload);
  291. }
  292. #endif
  293. }
  294. }
  295. #endif // defined(IR_RX_PIN)
  296. // -----------------------------------------------------------------------------
  297. void _irLoop() {
  298. #if defined(IR_RX_PIN)
  299. _irRXLoop();
  300. #endif
  301. #if MQTT_SUPPORT && defined(IR_TX_PIN)
  302. _irTXLoop();
  303. #endif
  304. }
  305. void irSetup() {
  306. #if defined(IR_RX_PIN)
  307. _ir_receiver.enableIRIn();
  308. DEBUG_MSG_P(PSTR("[IR] Receiver initialized \n"));
  309. #endif
  310. #if MQTT_SUPPORT && defined(IR_TX_PIN)
  311. _ir_sender.begin();
  312. mqttRegister(_irMqttCallback);
  313. DEBUG_MSG_P(PSTR("[IR] Transmitter initialized \n"));
  314. #endif
  315. espurnaRegisterLoop(_irLoop);
  316. }
  317. #endif // IR_SUPPORT