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.

422 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. #include "ir.h"
  37. #if IR_SUPPORT
  38. #include "light.h"
  39. #include "mqtt.h"
  40. #include "relay.h"
  41. #if defined(IR_RX_PIN)
  42. IRrecv _ir_receiver(IR_RX_PIN, IR_BUFFER_SIZE, IR_TIMEOUT, true);
  43. decode_results _ir_results;
  44. #endif // defined(IR_RX_PIN)
  45. #if defined(IR_TX_PIN)
  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(unsigned 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(unsigned 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 (unsigned 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. #if defined(IR_RX_PIN)
  132. _ir_receiver.disableIRIn();
  133. #endif
  134. _ir_sender.sendRaw(_ir_raw, count, _ir_freq);
  135. if (_ir_repeat==0) { // no repeat, cleaning array, enabling receiver
  136. free(_ir_raw);
  137. #if defined(IR_RX_PIN)
  138. _ir_receiver.enableIRIn();
  139. #endif
  140. } else if (col>2) { // repeat with repeat_code
  141. DEBUG_MSG_P(PSTR("[IR] Repeat codes count: %d\n"), _ir_repeat_size);
  142. free(_ir_raw);
  143. _ir_raw = (uint16_t*)calloc(_ir_repeat_size, sizeof(uint16_t));
  144. String value = ""; // for populating values of array from comma separated string
  145. int j = 0; // for populating values of array from comma separated string
  146. len = data.length(); //redifining length to full lenght
  147. // populating repeat code array from part of MQTT string
  148. for (unsigned int i = col+1; i < len; i++) {
  149. value = value + data[i];
  150. if ((payload[i] == ',') || (i == len - 1)) {
  151. _ir_raw[j]= value.toInt();
  152. value = "";
  153. j++;
  154. }
  155. }
  156. } else { // if repeat code not specified (col<=2) repeat with current main code
  157. _ir_repeat_size = count;
  158. }
  159. #else
  160. _ir_repeat = 0;
  161. if (col > 0) {
  162. _ir_type = data.toInt();
  163. _ir_code = strtoul(data.substring(col+1).c_str(), NULL, 10);
  164. col = data.indexOf(":", col+1);
  165. if (col > 0) {
  166. _ir_bits = data.substring(col+1).toInt();
  167. col = data.indexOf(":", col+1);
  168. if (col > 2) {
  169. _ir_repeat = data.substring(col+1).toInt();
  170. } else {
  171. _ir_repeat = IR_REPEAT;
  172. }
  173. }
  174. }
  175. if (_ir_repeat > 0) {
  176. DEBUG_MSG_P(PSTR("[IR] IROUT: %d:%lu:%d:%d\n"), _ir_type, (unsigned long) _ir_code, _ir_bits, _ir_repeat);
  177. } else {
  178. DEBUG_MSG_P(PSTR("[IR] Wrong MQTT payload format (%s)\n"), payload);
  179. }
  180. #endif // IR_USE_RAW
  181. } // end of match topic
  182. } // end of MQTT message
  183. } //end of function
  184. void _irTXLoop() {
  185. static uint32_t last = 0;
  186. if ((_ir_repeat > 0) && (millis() - last > _ir_delay)) {
  187. last = millis();
  188. // Send message
  189. #if IR_USE_RAW
  190. _ir_sender.sendRaw(_ir_raw, _ir_repeat_size, _ir_freq);
  191. #else
  192. _ir_sender.send(_ir_type, _ir_code, _ir_bits);
  193. #endif
  194. // Update repeat count
  195. --_ir_repeat;
  196. if (0 == _ir_repeat) {
  197. #if IR_USE_RAW
  198. free(_ir_raw);
  199. #endif
  200. #if defined(IR_RX_PIN)
  201. _ir_receiver.enableIRIn();
  202. #endif
  203. }
  204. }
  205. }
  206. #endif // MQTT_SUPPORT && defined(IR_TX_PIN)
  207. // Receiving
  208. #if defined(IR_RX_PIN)
  209. void _irProcess(unsigned char type, unsigned long code) {
  210. #if IR_BUTTON_SET > 0
  211. boolean found = false;
  212. for (unsigned char i = 0; i < IR_BUTTON_COUNT ; i++) {
  213. uint32_t button_code = pgm_read_dword(&IR_BUTTON[i][0]);
  214. if (code == button_code) {
  215. unsigned long button_action = pgm_read_dword(&IR_BUTTON[i][1]);
  216. unsigned long button_value = pgm_read_dword(&IR_BUTTON[i][2]);
  217. switch (button_action) {
  218. #if RELAY_SUPPORT
  219. case IR_BUTTON_ACTION_STATE:
  220. relayStatus(0, button_value);
  221. break;
  222. case IR_BUTTON_ACTION_TOGGLE:
  223. relayToggle(button_value);
  224. break;
  225. #endif // RELAY_SUPPORT == 1
  226. #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
  227. case IR_BUTTON_ACTION_BRIGHTER:
  228. lightBrightnessStep(button_value ? 1 : -1);
  229. lightUpdate(true, true);
  230. nice_delay(150); //debounce
  231. break;
  232. case IR_BUTTON_ACTION_RGB:
  233. lightColor(button_value);
  234. lightUpdate(true, true);
  235. break;
  236. /*
  237. #if LIGHT_PROVIDER == LIGHT_PROVIDER_FASTLED
  238. case IR_BUTTON_ACTION_EFFECT:
  239. _buttonAnimMode(button_value);
  240. break;
  241. #endif
  242. */
  243. /*
  244. case IR_BUTTON_ACTION_HSV:
  245. lightColor(button_value);
  246. break;
  247. */
  248. }
  249. #endif // LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
  250. found = true;
  251. break;
  252. }
  253. }
  254. if (!found) {
  255. DEBUG_MSG_P(PSTR("[IR] Code does not match any action\n"));
  256. }
  257. #endif
  258. }
  259. void _irRXLoop() {
  260. if (_ir_receiver.decode(&_ir_results)) {
  261. _ir_receiver.resume(); // Receive the next value
  262. // Debounce
  263. static unsigned long last_time = 0;
  264. if (millis() - last_time < IR_DEBOUNCE) return;
  265. last_time = millis();
  266. #if IR_USE_RAW
  267. // Check code
  268. if (_ir_results.rawlen < 1) return;
  269. char * payload;
  270. String value = "";
  271. for (int i = 1; i < _ir_results.rawlen; i++) {
  272. if (i>1) value = value + ",";
  273. value = value + String(_ir_results.rawbuf[i] * RAWTICK);
  274. }
  275. payload = const_cast<char*>(value.c_str());
  276. #else
  277. // Check code
  278. if (_ir_results.value < 1) return;
  279. if (_ir_results.decode_type < 1) return;
  280. if (_ir_results.bits < 1) return;
  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