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.

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