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.

420 lines
14 KiB

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