|
|
- /*
-
- IR MODULE
-
- Copyright (C) 2018 by Alexander Kolesnikov (raw and MQTT implementation)
- Copyright (C) 2017-2019 by François Déchery
- Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
-
- -----------------------------------------------------------------------------
- Configuration
- -----------------------------------------------------------------------------
-
- To enable transmit functions define IR_TX_PIN
- To enable receiver functions define IR_RX_PIN
- MQTT input topic: {root}/irin
- MQTT output topic: {root}/irout/set
-
- --------------------------------------------------------------------------------
- MQTT messages
- --------------------------------------------------------------------------------
-
- Decoded messages:
-
- Transmitting:
- Payload: 2:121944:32:1 (<type>:<code>:<bits>[:<repeat>])
- The repeat value is optional and defaults to 1
-
- Receiving:
- Payload: 2:121944:32 (<type>:<code>:<bits>)
-
- Raw messages:
-
- Transmitting:
- Payload: 1000,1000,1000,1000,1000,DELAY,COUNT,FREQ:500,500,500,500,500
- | IR codes | | IR repeat codes |
- codes - time in microseconds when IR LED On/Off. First value - ON, second - Off ...
- DELAY - delay in milliseconds between sending repeats
- COUNT - how many repeats send. Max 120.
- FREQ - modulation frequency. Usually 38kHz. You may set 38, it means 38kHz or set 38000, it meant same.
- Repeat codes is optional. You may omit ":" and codes. In this case if repeat count > 0 we repeat main code.
-
- Receiving:
- Payload: 1000,1000,1000,1000,1000
- | IR codes |
-
- --------------------------------------------------------------------------------
- */
-
- #if IR_SUPPORT
-
- #include "relay.h"
-
- #include <IRremoteESP8266.h>
-
- #if defined(IR_RX_PIN)
-
- #include <IRrecv.h>
- IRrecv _ir_receiver(IR_RX_PIN, IR_BUFFER_SIZE, IR_TIMEOUT, true);
-
- decode_results _ir_results;
-
- #endif // defined(IR_RX_PIN)
-
- #if defined(IR_TX_PIN)
-
- #include <IRsend.h>
- IRsend _ir_sender(IR_TX_PIN);
-
- #if IR_USE_RAW
- uint16_t _ir_freq = 38; // IR modulation freq. for sending codes and repeat codes
- uint8_t _ir_repeat_size = 0; // size of repeat array
- uint16_t * _ir_raw; // array for sending codes and repeat codes
- #else
- uint8_t _ir_type = 0; // Type of encoding
- uint64_t _ir_code = 0; // Code to transmit
- uint16_t _ir_bits = 0; // Code bits
- #endif
-
- uint8_t _ir_repeat = 0; // count of times repeating of repeat_code
- uint32_t _ir_delay = IR_DELAY; // delay between repeat codes
-
- #endif // defined(IR_TX_PIN)
-
- // MQTT to IR
- #if MQTT_SUPPORT && defined(IR_TX_PIN)
-
- void _irMqttCallback(unsigned int type, const char * topic, const char * payload) {
-
- if (type == MQTT_CONNECT_EVENT) {
- mqttSubscribe(MQTT_TOPIC_IROUT);
- }
-
- if (type == MQTT_MESSAGE_EVENT) {
- String t = mqttMagnitude((char *) topic);
-
- // Match topic
- if (t.equals(MQTT_TOPIC_IROUT)) {
-
- String data = String(payload);
- unsigned int len = data.length();
- int col = data.indexOf(":"); // position of ":" which means repeat_code
-
- #if IR_USE_RAW
-
- unsigned char count = 1; // count of code values for allocating array
-
- if (col > 2) { // count & validating repeat code
-
- _ir_repeat_size = 1;
-
- // count & validate repeat-string
- for(unsigned int i = col+1; i < len; i++) {
- if (i < len-1) {
- if ( payload[i] == ',' && isDigit(payload[i+1]) && i>0 ) { //validate string
- _ir_repeat_size++;
- } else if (!isDigit(payload[i])) {
- // Error in repeat_code. Use comma separated unsigned integer values.
- // Last three is repeat delay, repeat count(<120) and frequency.
- // After all you may write ':' and specify repeat code followed by comma.
- DEBUG_MSG_P(PSTR("[IR] Error in repeat code.\n"));
- return;
- }
- }
- }
-
- len = col; //cut repeat code from main code processing
-
- } // end of counting & validating repeat code
-
- // count & validate main code string
- for(unsigned int i = 0; i < len; i++) {
- if (i<len-1) {
- if ( payload[i] == ',' && isDigit(payload[i+1]) && i>0 ) { //validate string
- count++;
- } else if (!isDigit(payload[i])) {
- // Error in main code. Use comma separated unsigned integer values.
- // Last three is repeat delay, repeat count(<120) and frequency.
- // After all you may write ':' and specify repeat code followed by comma.
- DEBUG_MSG_P(PSTR("[IR] Error in main code.\n"));
- return;
- }
- }
-
- }
-
- _ir_raw = (uint16_t*)calloc(count, sizeof(uint16_t)); // allocating array for main codes
- String value = ""; // for populating values of array from comma separated string
- int j = 0; // for populating values of array from comma separated string
-
- // populating main code array from part of MQTT string
- for (unsigned int i = 0; i < len; i++) {
- if (payload[i] != ',') {
- value = value + data[i];
- }
- if ((payload[i] == ',') || (i == len - 1)) {
- _ir_raw[j]= value.toInt();
- value = "";
- j++;
- }
- }
-
- // if count>3 then we have values, repeat delay, count and modulation frequency
- _ir_repeat=0;
- if (count>3) {
- 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.
- _ir_freq = _ir_raw[count-1];
- _ir_repeat = _ir_raw[count-2];
- _ir_delay = _ir_raw[count-3];
- count = count - 3;
- }
- }
-
- DEBUG_MSG_P(PSTR("[IR] Raw IR output %d codes, repeat %d times on %d(k)Hz freq.\n"), count, _ir_repeat, _ir_freq);
-
- #if defined(IR_RX_PIN)
- _ir_receiver.disableIRIn();
- #endif
- _ir_sender.sendRaw(_ir_raw, count, _ir_freq);
-
- if (_ir_repeat==0) { // no repeat, cleaning array, enabling receiver
- free(_ir_raw);
- #if defined(IR_RX_PIN)
- _ir_receiver.enableIRIn();
- #endif
- } else if (col>2) { // repeat with repeat_code
-
- DEBUG_MSG_P(PSTR("[IR] Repeat codes count: %d\n"), _ir_repeat_size);
-
- free(_ir_raw);
- _ir_raw = (uint16_t*)calloc(_ir_repeat_size, sizeof(uint16_t));
-
- String value = ""; // for populating values of array from comma separated string
- int j = 0; // for populating values of array from comma separated string
- len = data.length(); //redifining length to full lenght
-
- // populating repeat code array from part of MQTT string
- for (unsigned int i = col+1; i < len; i++) {
- value = value + data[i];
- if ((payload[i] == ',') || (i == len - 1)) {
- _ir_raw[j]= value.toInt();
- value = "";
- j++;
- }
- }
- } else { // if repeat code not specified (col<=2) repeat with current main code
- _ir_repeat_size = count;
- }
-
- #else
-
- _ir_repeat = 0;
-
- if (col > 0) {
-
- _ir_type = data.toInt();
- _ir_code = strtoul(data.substring(col+1).c_str(), NULL, 10);
-
- col = data.indexOf(":", col+1);
- if (col > 0) {
- _ir_bits = data.substring(col+1).toInt();
- col = data.indexOf(":", col+1);
- if (col > 2) {
- _ir_repeat = data.substring(col+1).toInt();
- } else {
- _ir_repeat = IR_REPEAT;
- }
- }
- }
-
- if (_ir_repeat > 0) {
- DEBUG_MSG_P(PSTR("[IR] IROUT: %d:%lu:%d:%d\n"), _ir_type, (unsigned long) _ir_code, _ir_bits, _ir_repeat);
- } else {
- DEBUG_MSG_P(PSTR("[IR] Wrong MQTT payload format (%s)\n"), payload);
- }
-
- #endif // IR_USE_RAW
-
- } // end of match topic
-
- } // end of MQTT message
-
- } //end of function
-
- void _irTXLoop() {
-
- static uint32_t last = 0;
- if ((_ir_repeat > 0) && (millis() - last > _ir_delay)) {
- last = millis();
-
- // Send message
- #if IR_USE_RAW
- _ir_sender.sendRaw(_ir_raw, _ir_repeat_size, _ir_freq);
- #else
- _ir_sender.send(_ir_type, _ir_code, _ir_bits);
- #endif
-
- // Update repeat count
- --_ir_repeat;
- if (0 == _ir_repeat) {
- #if IR_USE_RAW
- free(_ir_raw);
- #endif
- #if defined(IR_RX_PIN)
- _ir_receiver.enableIRIn();
- #endif
- }
-
- }
-
- }
-
- #endif // MQTT_SUPPORT && defined(IR_TX_PIN)
-
- // Receiving
-
- #if defined(IR_RX_PIN)
-
- void _irProcess(unsigned char type, unsigned long code) {
-
- #if IR_BUTTON_SET > 0
-
- boolean found = false;
-
- for (unsigned char i = 0; i < IR_BUTTON_COUNT ; i++) {
-
- uint32_t button_code = pgm_read_dword(&IR_BUTTON[i][0]);
- if (code == button_code) {
-
- unsigned long button_mode = pgm_read_dword(&IR_BUTTON[i][1]);
- unsigned long button_value = pgm_read_dword(&IR_BUTTON[i][2]);
-
- if (button_mode == IR_BUTTON_MODE_STATE) {
- relayStatus(0, button_value);
- }
-
- if (button_mode == IR_BUTTON_MODE_TOGGLE) {
- relayToggle(button_value);
- }
-
- #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
-
- if (button_mode == IR_BUTTON_MODE_BRIGHTER) {
- lightBrightnessStep(button_value ? 1 : -1);
- nice_delay(150); //debounce
- }
-
- if (button_mode == IR_BUTTON_MODE_RGB) {
- lightColor((button_value >> 8) & 0xffffff);
- lightBrightness(button_value & 0xff);
- }
-
- /*
- #if LIGHT_PROVIDER == LIGHT_PROVIDER_FASTLED
- if (button_mode == IR_BUTTON_MODE_EFFECT) {
- _buttonAnimMode(button_value);
- }
- #endif
- */
-
- /*
- if (button_mode == IR_BUTTON_MODE_HSV) {
- lightColor(button_value);
- }
- */
-
- lightUpdate(true, true);
-
- #endif
-
- found = true;
- break;
-
- }
-
- }
-
- if (!found) {
- DEBUG_MSG_P(PSTR("[IR] Code does not match any action\n"));
- }
-
- #endif
-
- }
-
- void _irRXLoop() {
-
- if (_ir_receiver.decode(&_ir_results)) {
-
- _ir_receiver.resume(); // Receive the next value
-
- // Debounce
- static unsigned long last_time = 0;
- if (millis() - last_time < IR_DEBOUNCE) return;
- last_time = millis();
-
- #if IR_USE_RAW
- // Check code
- if (_ir_results.rawlen < 1) return;
- char * payload;
- String value = "";
- for (int i = 1; i < _ir_results.rawlen; i++) {
- if (i>1) value = value + ",";
- value = value + String(_ir_results.rawbuf[i] * RAWTICK);
- }
- payload = const_cast<char*>(value.c_str());
- #else
- // Check code
- if (_ir_results.value < 1) return;
- if (_ir_results.decode_type < 1) return;
- if (_ir_results.bits < 1) return;
- char payload[32];
- snprintf_P(payload, sizeof(payload), PSTR("%u:%lu:%u"), _ir_results.decode_type, (unsigned long) _ir_results.value, _ir_results.bits);
- #endif
-
- DEBUG_MSG_P(PSTR("[IR] IRIN: %s\n"), payload);
-
- #if not IR_USE_RAW
- _irProcess(_ir_results.decode_type, (unsigned long) _ir_results.value);
- #endif
-
- #if MQTT_SUPPORT
- if (strlen(payload)>0) {
- mqttSend(MQTT_TOPIC_IRIN, (const char *) payload);
- }
- #endif
-
- }
-
- }
-
- #endif // defined(IR_RX_PIN)
-
- // -----------------------------------------------------------------------------
-
- void _irLoop() {
- #if defined(IR_RX_PIN)
- _irRXLoop();
- #endif
- #if MQTT_SUPPORT && defined(IR_TX_PIN)
- _irTXLoop();
- #endif
- }
-
- void irSetup() {
-
- #if defined(IR_RX_PIN)
- _ir_receiver.enableIRIn();
- DEBUG_MSG_P(PSTR("[IR] Receiver initialized \n"));
- #endif
-
- #if MQTT_SUPPORT && defined(IR_TX_PIN)
- _ir_sender.begin();
- mqttRegister(_irMqttCallback);
- DEBUG_MSG_P(PSTR("[IR] Transmitter initialized \n"));
- #endif
-
- espurnaRegisterLoop(_irLoop);
-
- }
-
- #endif // IR_SUPPORT
|