Particle Photon Infrared signal cloner

Oh, sorry…

My bad:

Processing  ircloner.ino
Checking library IRremote...
Checking library IRTransmitter...
Installing library IRTransmitter 0.1.0 to lib/IRTransmitter ...
Installing library IRremote 0.0.3 to lib/IRremote ...
Library IRTransmitter 0.1.0 installed.
Library IRremote 0.0.3 installed.
Checking library SparkIntervalTimer...
Installing library SparkIntervalTimer 1.3.7 to lib/SparkIntervalTimer ...
Library SparkIntervalTimer 1.3.7 installed.
make -C ../modules/photon/user-part all
make[1]: Entering directory '/firmware/modules/photon/user-part'
make -C ../../../user 
make[2]: Entering directory '/firmware/user'
Building cpp file: src/ircloner.cpp
Invoking: ARM GCC CPP Compiler
mkdir -p ../build/target/user/platform-6-msrc/
arm-none-eabi-gcc -DSTM32_DEVICE -DSTM32F2XX -DPLATFORM_THREADING=1 -DPLATFORM_ID=6 -DPLATFORM_NAME=photon -DUSBD_VID_SPARK=0x2B04 -DUSBD_PID_DFU=0xD006 -DUSBD_PID_CDC=0xC006 -DSPARK_PLATFORM -g3 -gdwarf-2 -Os -mcpu=cortex-m3 -mthumb -DINCLUDE_PLATFORM=1 -DPRODUCT_ID=6 -DPRODUCT_FIRMWARE_VERSION=65535 -DUSE_STDPERIPH_DRIVER -DDFU_BUILD_ENABLE -DSYSTEM_VERSION_STRING=0.6.2 -DRELEASE_BUILD -I./inc -I../wiring/inc -I../system/inc -I../services/inc -I../communication/src -I../hal/inc -I../hal/shared -I../hal/src/photon -I../hal/src/stm32f2xx -I../hal/src/stm32 -I../hal/src/photon/api -I../platform/shared/inc -I../platform/MCU/STM32F2xx/STM32_USB_Host_Driver/inc -I../platform/MCU/STM32F2xx/STM32_StdPeriph_Driver/inc -I../platform/MCU/STM32F2xx/STM32_USB_OTG_Driver/inc -I../platform/MCU/STM32F2xx/STM32_USB_Device_Driver/inc -I../platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc -I../platform/MCU/shared/STM32/inc -I../platform/MCU/STM32F2xx/CMSIS/Include -I../platform/MCU/STM32F2xx/CMSIS/Device/ST/Include -I../dynalib/inc -Isrc -I./libraries -Isrc -Isrc -Isrc -Isrc -Ilib/SparkIntervalTimer/src -Ilib/IRTransmitter/src -Ilib/IRremote/src -I. -MD -MP -MF ../build/target/user/platform-6-msrc/ircloner.o.d -ffunction-sections -fdata-sections -Wall -Wno-switch -Wno-error=deprecated-declarations -fmessage-length=0 -fno-strict-aliasing -DSPARK=1 -DPARTICLE=1 -DSTART_DFU_FLASHER_SERIAL_SPEED=14400 -DSTART_YMODEM_FLASHER_SERIAL_SPEED=28800 -DSPARK_PLATFORM_NET=BCM9WCDUSI09 -fno-builtin-malloc -fno-builtin-free -fno-builtin-realloc  -DLOG_INCLUDE_SOURCE_INFO=1 -DPARTICLE_USER_MODULE -DUSE_THREADING=0 -DUSE_SPI=SPI -DUSE_CS=A2 -DUSE_SPI=SPI -DUSE_CS=A2 -DUSE_THREADING=0 -DUSER_FIRMWARE_IMAGE_SIZE=0x20000 -DUSER_FIRMWARE_IMAGE_LOCATION=0x80A0000 -DMODULAR_FIRMWARE=1 -DMODULE_VERSION=4 -DMODULE_FUNCTION=5 -DMODULE_INDEX=1 -DMODULE_DEPENDENCY=4,2,108 -D_WINSOCK_H -D_GNU_SOURCE -DLOG_MODULE_CATEGORY="\"app\""  -fno-exceptions -fno-rtti -fcheck-new -std=gnu++11 -c -o ../build/target/user/platform-6-msrc/ircloner.o src/ircloner.cpp
ircloner.ino: In function 'void loop()':
ircloner.ino:81:65: error: invalid types 'unsigned int[int]' for array subscript
../build/module.mk:267: recipe for target '../build/target/user/platform-6-msrc/ircloner.o' failed
make[2]: *** [../build/target/user/platform-6-msrc/ircloner.o] Error 1
make[2]: Leaving directory '/firmware/user'
../../../build/recurse.mk:11: recipe for target 'user' failed
make[1]: *** [user] Error 2
make[1]: Leaving directory '/firmware/modules/photon/user-part'
../build/recurse.mk:11: recipe for target 'modules/photon/user-part' failed
make: *** [modules/photon/user-part] Error 2

code1 is just a single unsigned int, but your function requires a an array unsigned int[int]
This is what the error message clearly states

So I guess you rather want

transmitter.Transmit(data, sizeof(data) / sizeof(data[0]));
1 Like

I get what you say…
Situation maybe is a bit more complex…

In my code I have two parts: the receiver and the transmitter.
In my normal loop I am receiving data.

When I check my serial monitor when I push the power off button I see:
1000C

I would like to save this information into a variable that then I’ll use to beam the same signal.

Is this an int also?
I think I should input in the transmitting function also the int lenght, like you suggested?

How can I do it dinamically (I mean that every command could have different lenght)?

I also have a doubt about a possible conversion to do:
I push the power button on the remote and I need to save the 1000C I see (maybe HEX code?) and transmit it back using int.

Maybe I need to convert the HEX (if 1000C is an HEX) to int?

I was able to write a more complete example to show the data I get (the switch works perfectly):

// IR Transmitter Library
#include <IRTransmitter.h>
// IR Receiver Library
#include <IRremote.h>

// Here we specify the infrared led pin
#define IR_PIN D4
// Here we specify the visual feedback led pin
#define LED_PIN D7

// Here we specify the infrared receiver pin
int RECV_PIN = D2;


// Stored codes variables
unsigned int code1 = 0;

// Initializing IRReceiver
IRrecv irrecv(RECV_PIN);
decode_results results;

// Initializing IRTransmitter
IRTransmitter transmitter(IR_PIN, LED_PIN);


void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
}

void loop() {

  // Receiving IR signal and printing it using serial port
  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    switch(results.value)
  {
    case 0x1000C:   Serial.println("Power button"); break;
    case 0xC:       Serial.println("Power button"); break;
    case 0x11:     Serial.println("Button 0"); break;
    case 0x1:       Serial.println("Button 1"); break;
    case 0x10001:       Serial.println("Button 1"); break;
    case 0x2:       Serial.println("Button 2"); break;
    case 0x10002:       Serial.println("Button 2"); break;
    case 0x3:     Serial.println("Button 3"); break;
    case 0x10003:     Serial.println("Button 3"); break;
    case 0x410:     Serial.println("Button 4"); break;
    case 0xC10:     Serial.println("Button 5"); break;
    case 0x210:     Serial.println("Button 6"); break;
    case 0xA10:     Serial.println("Button 7"); break;
    case 0x610:     Serial.println("Button 8"); break;
    case 0x111:     Serial.println("Button 9"); break;
    default:        Serial.println("Unknown button");
  }
     if (code1 == 0) {
        code1 = results.value;
    }
    irrecv.resume(); // Receive the next value
  }
 
 
if (code1 != 0) {
      // Sending via IR data    
      //transmitter.Transmit(data, sizeof(data) / sizeof(data[0]));
      //transmitter.Transmit(code1, sizeof(code1) / sizeof(code1[0]));
  }

  // Sending via IR data (using example data, works)   
  //transmitter.Transmit(data, sizeof(data) / sizeof(data[0]));

}

When you look at data you’ll see that this holds a lot more data than one single int ever can.
This is a list of pulse/pause times the receiver saw or a transmitter has to produce.

You’d need to look into the receiver library code to understand how the return value is produced and what it means but I’m quite positive that this is not the raw data of the IR signal you’d need to reproduce the IR command.

1 Like

You’re right indeed!

I’ve been looking better into the receiving library, IRREMOTE and it seems like it is also able to send signal so I could be ok just using it.

My C is very weak so I am struggling a bit, I will investigate and write back findings.

Really thanks for now :slight_smile:

1 Like

No luck :confused:

I have been trying and researching a lot and in the end I’ve found this code (got it from this page: https://github.com/z3t0/Arduino-IRremote/blob/master/examples/IRrecord/IRrecord.ino).
It seems to work perfectly: If I push BUTTON_PIN it goes in record mode.
If I press a button on the remote during record mode I see it correctly in the serial.

Then I stop pushing BUTTON_PIN and the code is sent via IR_LED.

I’ve also put STATUS_LED to have a quick visual, all fine.

If I use my phone as a camera to check IR_LED for activity it seems to work just fine but my tv will not turn on…

I think that the key of the issue is here, when PWM pin is discussed.

Which is the corresponding port for PWM pin 3?

/*
 * IRrecord: record and play back IR signals as a minimal 
 * An IR detector/demodulator must be connected to the input RECV_PIN.
 * An IR LED must be connected to the output PWM pin 3.
 * A button must be connected to the input BUTTON_PIN; this is the
 * send button.
 * A visible LED can be connected to STATUS_PIN to provide status.
 *
 * The logic is:
 * If the button is pressed, send the IR code.
 * If an IR code is received, record it.
 *
 * Version 0.11 September, 2009
 * Copyright 2009 Ken Shirriff
 * http://arcfn.com
 */


    #include <IRremote.h>

    int RECV_PIN = D2;
    int LED_PIN = D4;
    int BUTTON_PIN = D1;
    int STATUS_PIN = D7;


    IRrecv irrecv(RECV_PIN);
    IRsend irsend;

    decode_results results;

    void setup()
    {
      Serial.begin(9600);
      irrecv.enableIRIn(); // Start the receiver
      pinMode(BUTTON_PIN, INPUT);
      pinMode(STATUS_PIN, OUTPUT);
      pinMode(LED_PIN, OUTPUT);
    }

    // Storage for the recorded code
    int codeType = -1; // The type of code
    unsigned long codeValue; // The code value if not raw
    unsigned int rawCodes[RAWBUF]; // The durations if raw
    int codeLen; // The length of the code
    int toggle = 0; // The RC5/6 toggle state

    // Stores the code for later playback
    // Most of this code is just logging
    void storeCode(decode_results *results) {
      codeType = results->decode_type;
      int count = results->rawlen;
      if (codeType == UNKNOWN) {
        Serial.println("Received unknown code, saving as raw");
        codeLen = results->rawlen - 1;
        // To store raw codes:
        // Drop first value (gap)
        // Convert from ticks to microseconds
        // Tweak marks shorter, and spaces longer to cancel out IR receiver distortion
        for (int i = 1; i <= codeLen; i++) {
          if (i % 2) {
            // Mark
            rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK - MARK_EXCESS;
            Serial.print(" m");
          } 
          else {
            // Space
            rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK + MARK_EXCESS;
            Serial.print(" s");
          }
          Serial.print(rawCodes[i - 1], DEC);
        }
        Serial.println("");
      }
      else {
        if (codeType == NEC) {
          Serial.print("Received NEC: ");
          if (results->value == REPEAT) {
            // Don't record a NEC repeat value as that's useless.
            Serial.println("repeat; ignoring.");
            return;
          }
        } 
        else if (codeType == SONY) {
          Serial.print("Received SONY: ");
        } 
        else if (codeType == PANASONIC) {
          Serial.print("Received PANASONIC: ");
        }
        else if (codeType == JVC) {
          Serial.print("Received JVC: ");
        }
        else if (codeType == RC5) {
          Serial.print("Received RC5: ");
        } 
        else if (codeType == RC6) {
          Serial.print("Received RC6: ");
        } 
        else {
          Serial.print("Unexpected codeType ");
          Serial.print(codeType, DEC);
          Serial.println("");
        }
        Serial.println(results->value, HEX);
        codeValue = results->value;
        codeLen = results->bits;
      }
    }

    void sendCode(int repeat) {
      if (codeType == NEC) {
        if (repeat) {
          irsend.sendNEC(REPEAT, codeLen);
          Serial.println("Sent NEC repeat");
        } 
        else {
          irsend.sendNEC(codeValue, codeLen);
          Serial.print("Sent NEC ");
          Serial.println(codeValue, HEX);
        }
      } 
      else if (codeType == SONY) {
        irsend.sendSony(codeValue, codeLen);
        Serial.print("Sent Sony ");
        Serial.println(codeValue, HEX);
      } 
      else if (codeType == PANASONIC) {
        irsend.sendPanasonic(codeValue, codeLen);
        Serial.print("Sent Panasonic");
        Serial.println(codeValue, HEX);
      }
      else if (codeType == JVC) {
        irsend.sendJVC(codeValue, codeLen, false);
        Serial.print("Sent JVC");
        Serial.println(codeValue, HEX);
      }
      else if (codeType == RC5 || codeType == RC6) {
        if (!repeat) {
          // Flip the toggle bit for a new button press
          toggle = 1 - toggle;
        }
        // Put the toggle bit into the code to send
        codeValue = codeValue & ~(1 << (codeLen - 1));
        codeValue = codeValue | (toggle << (codeLen - 1));
        if (codeType == RC5) {
          Serial.print("Sent RC5 ");
          Serial.println(codeValue, HEX);
          irsend.sendRC5(codeValue, codeLen);
        } 
        else {
          irsend.sendRC6(codeValue, codeLen);
          Serial.print("Sent RC6 ");
          Serial.println(codeValue, HEX);
        }
      } 
      else if (codeType == UNKNOWN /* i.e. raw */) {
        // Assume 38 KHz
        irsend.sendRaw(rawCodes, codeLen, 38);
        Serial.println("Sent raw");
      }
    }

    int lastButtonState;

    void loop() {
      // If button pressed, send the code.
      int buttonState = digitalRead(BUTTON_PIN);
      if (lastButtonState == HIGH && buttonState == LOW) {
        Serial.println("Released");
        irrecv.enableIRIn(); // Re-enable receiver
      }

      if (buttonState) {
        Serial.println("Pressed, sending");
        digitalWrite(STATUS_PIN, HIGH);
        digitalWrite(LED_PIN, HIGH);
        sendCode(lastButtonState == buttonState);
        digitalWrite(STATUS_PIN, LOW);
        digitalWrite(LED_PIN, LOW);
        delay(50); // Wait a bit between retransmissions
      } 
      else if (irrecv.decode(&results)) {
        digitalWrite(STATUS_PIN, HIGH);
        digitalWrite(LED_PIN, HIGH);
        storeCode(&results);
        irrecv.resume(); // resume receiver
        digitalWrite(LED_PIN, LOW);
        digitalWrite(STATUS_PIN, LOW);
      }
      lastButtonState = buttonState;
    }

I am sorry to disturb again but I really can’t solve this riddle :frowning:

I can use successfully the IRTransmitter Photon Library to send the code but it only supports RAW.

On the other hand I can use IRRemote Photon Library to get the remote controller code but it doesn’t print te code in RAW but only in HEX (an example code looks like 1000C).

I’ve found a HEX decoder online but pasting my code: 1000C just throws an error:
http://www.convertstring.com/EncodeDecode/HexDecode

Was anybody able to solve this?

Edit:
I’ve been researching on the forum and the maximum expert seems to be @AnalysIR
Sorry for disturbing but maybe you can shed a light? :slight_smile:

I suggest you only use IRremote.

To get familiar with it, work thru all of the example sketches in the IRremote examples folder.

If you want to send using a HEX value, check out the sendNEC, sendSONY, send RC6 functions.

If you want to send using RAW use sendRAW.

You will find example sketches s included with the library & its best to work thru them.

PS: I am not as up to date on the Photon version of IRremote & if it is up to date.

1 Like

I think I can do anything I need with IRremote the only issue I have is to find out which is the Infrared Led PIN…

which is the Infrared Led PIN…

For IRremote ‘on Photon’ default IR Tx pin should be A5 (last time I checked!)
(Note: on our Photon IR shield it is the TX pin)

It is configured in IRremoteInt.h and you should be able to change it.

1 Like

Thanks for your help, it is deeply appreciated :slight_smile:

The only relevant part I can find in that file is:

// Particle
#elif defined(PARTICLE)
  #define IR_USE_TIMER_PARTICLE  // tx = pin 17

But I am not really sure on where to change it…
I think also pin 17 on the photon doesn’t exist…

…from my notes I have

timer#elif defined(IR_USE_TIMER_PARTICLE)
#define TIMER_PWM_PIN A5

If that line isnt in the library, try adding it in. Yo ucan also assign to most(?) other pins by changing A5 to another pin label. Of course you have to recompile and reflash the firmware

If that doesnt work just look up the pin maps for Photon…I have no particular expertise in doing that :slight_smile:
doing Serial.println(A5);

will give you the numerical assignment. repeat for every pin until you get 17.

Another test is to just print out the value for TIMER_PWM_PIN
doing Serial.println(TIMER_PWM_PIN);

and match it to the values you got above.

…sorry rushing out…

2 Likes

Thanks a LOT for the amazing input, I’ll report news :slight_smile:

1 Like

Hi, I had (and still have) the need for something similar and posted my findings here:


Cheers,
Gustavo.

1 Like

Has anyone been able to get this IR receiver to work? I am working on a similar project. Would really appreciate some help. I cannot find an IRreceiver library that has been ported to Photon yet.

Hi, I made it work and described my thoughts on the project above (or here).
Well, the library IRemote was already ported to the photon, so the “I made it work” was pretty easy to do - the stuff was hard to understand at the beginning, I must admit.
Cheers,
Gustavo.

I’ve tested both libraries getting receiver and sender to work with IR- the problem is, sadly, that the libraries don’t work together…

irrecv.enableIRIn() seems to create the problem. My theory is that it causes timing trouble when sending signals- the sender sends (verified by camera)- but the timing becomes shifted and therefore it doesn’t work.

I might try to create a disableIRin so that it’s possible to switch between sending and receiving.

I’ve tried putting in something that works using both libraries but then interrupted it long ago…
Here’s one of the versions of code I was fiddling with:

/*
 * IRCloner - Implementation of a IR cloner using IRTransmitter and IRremote
 * An IR detector/demodulator must be connected to the input RECV_PIN.
 * An IR LED must be connected to input IR_PIN
 * A LED must be connected to input LED_PIN
 */

// IR Transmitter Library
#include <IRTransmitter.h>
// IR Receiver Library
#include <IRremote.h>

// Here we specify the infrared led pin
#define IR_PIN D2
// Here we specify the visual feedback led pin
#define LED_PIN D7

// Here we specify the infrared receiver pin
int RECV_PIN = D6;


// Stored codes variables
unsigned int code1 = 0;

IRsend irsend;

//IRsend irSend = IRsend(D0);

// Initializing IRReceiver
IRrecv irrecv(RECV_PIN);
decode_results results;

// Initializing IRTransmitter
IRTransmitter transmitter(IR_PIN, LED_PIN);

// Raw data example
unsigned int data[67] = {9000, 4450, 550, 550, 600, 500, 600, 550, 550, 1650, 600, 550, 550, 550, 600, 500, 600, 550,
                            600, 1600, 600, 1650, 600, 1650, 600, 500, 600, 1650, 600, 1600, 600, 1650, 600, 1650, 600,
                            500, 600, 1650, 600, 1650, 550, 550, 600, 1650, 550, 550, 600, 500, 600, 550, 550, 1650,
                            600, 550, 550, 550, 600, 1650, 550, 550, 600, 1650, 550, 1650, 650, 1600,
                            600};  // NEC 10EF6897

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
}

void loop() {

  // Receiving IR signal and printing it using serial port
  if (irrecv.decode(&results)) {
      Serial.println(results.value, RAW);
    switch(results.value)
  {
    case 0x1000C:   Serial.println("Power button"); break;
    case 0xC:       Serial.println("Power button"); break;
    case 0x11:     Serial.println("Button 0"); break;
    case 0x1:       Serial.println("Button 1"); break;
    case 0x10001:       Serial.println("Button 1"); break;
    case 0x2:       Serial.println("Button 2"); break;
    case 0x10002:       Serial.println("Button 2"); break;
    case 0x3:     Serial.println("Button 3"); break;
    case 0x10003:     Serial.println("Button 3"); break;
    case 0x410:     Serial.println("Button 4"); break;
    case 0xC10:     Serial.println("Button 5"); break;
    case 0x210:     Serial.println("Button 6"); break;
    case 0xA10:     Serial.println("Button 7"); break;
    case 0x610:     Serial.println("Button 8"); break;
    case 0x111:     Serial.println("Button 9"); break;
    default:        Serial.println("Unknown button");
  }
     if (code1 == 0) {
        code1 = results.value;
    }
    irrecv.resume(); // Receive the next value
  }
 
// irsend.sendSony(0xa90, 12);
 
 //transmitter.Transmit(data, sizeof(data) / sizeof(data[0]));
 
 //for (int i = 0; i < 3; i++) 
//{
    //irsend.sendSony((unsigned long)0xa90, 12); // Sony TV power code
    //irsend.sendRC6(0x1000C, 12);
    //delay(40);
//}
 
 /*
if (code1 != 0) {
      // Sending via IR data    
      transmitter.Transmit(code1, sizeof(code1) / sizeof(code1[0]));
  }

  // Sending via IR data (using example data, works)   
  //transmitter.Transmit(data, sizeof(data) / sizeof(data[0]));

*/

}

For anyone else that stumbles here, it might be useful to have a working version of both of these.

If you want to READ (aka RECEIVE) IR codes, check out something like the “VMA317” module (https://www.vellemanstore.com/en/velleman-vma317-arduino-compatible-ir-infrared-37-9-khz-receiver-2-pieces) – they are ~$2-3/each. The benefit is a nice clean 3 wire (Vcc, GND, and “DATA”) interface.

The code is:

// This #include statement was automatically added by the Particle IDE.
#include <IRremote.h>

// NOTE: Need 5V for VIN

int RECV_PIN = D0;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup() {
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
}

void loop() {
  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    //Serial.println(results.value);
    //Serial.println(results.value, BIN);
    irrecv.resume(); // Receive the next value
  }
}

If you want to SEND (aka TRANSMIT) IR codes, check out something like the “VMA316” module (https://www.vellemanstore.com/en/velleman-vma316-arduino-compatible-infrared-transmitter-module-2-pieces) – they are ~$2-3/each. The benefit again is a nice clean 3 wire (Vcc, GND, and “DATA”) interface.

The code is:

// This #include statement was automatically added by the Particle IDE.
#include <IRremote.h>

// Send Pin is A5 (https://www.hackster.io/gusgonnet/infrared-replicator-3c52d9)
// NOTE: Must send each command at least TWICE for most devices to receive it. Wait between sends!
IRsend irsend;

void setup() {
}

void loop() {
    
    // Must send twice for it to work!
    // NEC is 32 bits, and the HEX (0xSOMETHING) is straight from your receiver above.
    irsend.sendNEC(0x12345678, 32);
    irsend.sendNEC(0x12345678, 32);
    delay(5000); //5 second delay between each signal burst
}
2 Likes

Hi guys, I wanted to add as well my project shared here:

Thanks!
Gustavo.

1 Like