IR Sensor only reading every other button press
-
Hi,
I am trying to pass IR data from my TV remote to my controller (Home Assistant) for later processing.
I am using a TSOP38238 receiver connected to D3 on an arduino pro mini. The pro mini is using two other sensors (lux and temp/humidity) connected via i2c which are pulled every 90 seconds by the arduino. For brevity I'll omit their code, let me know if you need to see it anyway.
The arduino sleeps and is woken up by an interrupt if the IR-sensor receives data. The weird thing is though: The arduino wakes up on every signal from the TV remote (LG TV) but only receives every other signal.
Here is the output of the serial monitor:
20:20:55.561 -> 20:20:55.561 -> __ __ ____ 20:20:55.595 -> | \/ |_ _/ ___| ___ _ __ ___ ___ _ __ ___ 20:20:55.595 -> | |\/| | | | \___ \ / _ \ `_ \/ __|/ _ \| `__/ __| 20:20:55.595 -> | | | | |_| |___| | __/ | | \__ \ _ | | \__ \ 20:20:55.595 -> |_| |_|\__, |____/ \___|_| |_|___/\___/|_| |___/ 20:20:55.595 -> |___/ 2.4.0-alpha 20:20:55.595 -> 20:21:01.036 -> Tempsensor started 20:21:01.036 -> UPDATE_INTERVAL:90000 20:21:06.079 -> wake_reason=1 20:21:06.079 -> IR Processing done-------------------- 20:21:08.369 -> wake_reason=1 20:21:08.369 -> 20DF4EB 20:21:08.468 -> IR Processing done-------------------- 20:21:10.525 -> wake_reason=1 20:21:10.525 -> IR Processing done-------------------- 20:21:11.686 -> wake_reason=1 20:21:11.686 -> 20DF8E7 20:21:11.819 -> IR Processing done-------------------- 20:21:13.379 -> wake_reason=1 20:21:13.379 -> IR Processing done-------------------- 20:21:14.607 -> wake_reason=1 20:21:14.607 -> 20DFC63 20:21:14.706 -> IR Processing done-------------------- 20:21:16.033 -> wake_reason=1 20:21:16.033 -> IR Processing done-------------------- 20:21:16.929 -> wake_reason=1 20:21:16.929 -> 20DF867 20:21:17.029 -> IR Processing done--------------------
I pressed four different buttons on the remote, each one twice.
Here is the code, please let me know what I am doing wrong:
/** * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad <henrik.ekblad@mysensors.org> * Copyright (C) 2013-2015 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * ******************************* * * REVISION HISTORY * Version 1.0: Yveaux * * DESCRIPTION * This sketch provides an example of how to implement a humidity/temperature * sensor using a Si7021 sensor. * * For more information, please visit: * http://www.mysensors.org/build/humiditySi7021 * */ // Enable debug prints //#define MY_DEBUG #define MY_OWN_DEBUG #ifndef MY_OWN_DEBUG //disable serial in production compile, potentially saves few uA in sleep mode #define MY_DISABLED_SERIAL #endif // Enable and select radio type attached #define MY_RADIO_RFM69 #define MY_IS_RFM69HW #define MY_RFM69_NEW_DRIVER #define MY_NODE_ID 3 #include <MySensors.h> // IR specific setup #include <IRremote.h> int RECV_PIN = 3; IRrecv irrecv(RECV_PIN); decode_results ircode; const char * TYPE2STRING[] = { "UNKONWN", "RC5", "RC6", "NEC", "Sony", "Panasonic", "JVC", "SAMSUNG", "Whynter", "AIWA RC T501", "LG", "Sanyo", "Mitsubishi", "Dish", "Sharp", "Denon" }; #define Type2String(x) TYPE2STRING[x < 0 ? 0 : x] #define AddrTxt F(" addres: 0x") #define ValueTxt F(" value: 0x") #define NATxt F(" - not implemented/found") unsigned long last_value; // IR specific setup end #define CHILD_ID_HUM 0 #define CHILD_ID_TEMP 1 #define CHILD_ID_LUX 2 #define CHILD_ID_IR 3 #define SKETCH_NAME "mysensors_wohnzimmer_main" #define SKETCH_MAJOR_VER "1" #define SKETCH_MINOR_VER "0" static bool metric = true; int BATTERY_SENSE_PIN = A0; // select the input pin for the battery sense point int oldBatteryPcnt = 0; float lastHum = 0; float lastTemp = 0; int lastLux = 0; // Sleep time between sensor updates (in milliseconds) static const unsigned long UPDATE_INTERVAL = 90000; #include <SI7021.h> #include <BH1750.h> static SI7021 tempsensor; BH1750 lightmeter; // Change to V_LIGHT if you use S_LIGHT in presentation below MyMessage msgHum(CHILD_ID_HUM, V_HUM); MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP); MyMessage msgLux(CHILD_ID_LUX, V_LEVEL); MyMessage msgIrRecord(CHILD_ID_IR, V_IR_RECEIVE); void presentation() { // Send the sketch version information to the gateway and Controller sendSketchInfo(SKETCH_NAME, SKETCH_MAJOR_VER "." SKETCH_MINOR_VER); present(CHILD_ID_HUM, S_HUM); present(CHILD_ID_TEMP, S_TEMP); present(CHILD_ID_LUX, S_LIGHT_LEVEL); present(CHILD_ID_IR, S_IR); } void setup() { //Serial.begin(9600); //Serial.print("Starting: "); while (not tempsensor.begin()) { Serial.println(F("Temperaturesensor not detected!")); delay(5000); } #ifdef MY_OWN_DEBUG Serial.println("Tempsensor started"); #endif lightmeter.begin(); #ifdef MY_OWN_DEBUG Serial.print("UPDATE_INTERVAL:");Serial.println(UPDATE_INTERVAL); #endif irrecv.enableIRIn(); } void loop(){ int8_t wake_reason; sleep_bod_disable();//disable BOD - saves~ 15uA wake_reason = smartSleep(RECV_PIN-2, CHANGE, UPDATE_INTERVAL); #ifdef MY_OWN_DEBUG Serial.print("wake_reason=");Serial.println(wake_reason); #endif if (wake_reason == 1){ //woken up by interrupt on d3 ir_received(); } else{ //woken by update_interval update_interval(); } } void ir_received(){ if (irrecv.decode(&ircode)) { unsigned long ir_value = ircode.value; if (ir_value == REPEAT) //if repeat-code: send last code { ir_value = last_value; } else{ //if not: save new value as last value last_value = ir_value; } Serial.println(ir_value,HEX); delay(100); send(msgIrRecord.set(ir_value)); irrecv.resume(); // Receive the next value } Serial.println("IR Processing done--------------------"); } void update_interval() { //removed for brevity }
-
@kiesel Did you learn the codes yourself?
Some remotes (panasonic for example) will send a different code each time the button is pressed. They do this by having 2 codes for each button.
First time you press a button it sends code from the 'A' set and the next press of the button sends the 'B' set.
So it may be the same for the remote you have. If so you need to learn both sets of IR code and then implement a check in your sketch (a simple if comparison should be enough).....
I have also found that replacing irrecv.resume(); with irrecv.enableIRIn(); might help. Also to stop the reveive function when you have got a code, send a dummy ir message and then re-enable the ir reveiver as I just suggested.
-
I used the sketch "IRrecvDump" from the IRremote library to verify that only one code is sent per button press, so I don't think that's the problem.
With that sketch the same code is written to the serial monitor every time I press the same button.
The issue is that code uses polling and I want the arduino to sleep because it is a battery powered node.
/edit: irrecv.enableIRIn(); didn't make a difference unfortunately.
-
I think this is solved: It appears that the interrupt wakes the arduino who then queries the sensor before the full code is received. I added a
delay(100);
to give it a bit more time to read the data.
void ir_received(){ delay(100); if (irrecv.decode(&ircode)) { //#ifdef MY_OWN_DEBUG //dump(&ircode); //#endif unsigned long ir_value = ircode.value; if (ir_value == REPEAT) //if repeat-code: send last code { ir_value = last_value; } else{ //if not: save new value as last value last_value = ir_value; } Serial.println(ir_value,HEX); send(msgIrRecord.set(ir_value)); } //delay(100); irrecv.resume(); // Receive the next value Serial.println("IR Processing done--------------------"); }
If anybody has a better idea please let me know.
-
@kiesel Good work on finding the issue. Delay will block the cpu from performing other tasks (maybe that is what you want). Usually in mysensors we use wait(100); instead.
I have just finished my first IR send and receive node and have another 2 to build this weekend (hopefully).....
-
I didn't know that delay blocked, good to know, thanks. I have nothing that's supposed to run in the background so delay works for the time being
Congrats on the node! Is the code available somewhere? I'd like to take a look. Always good to learn new stuff.
-
@kiesel You are welcome! - We are all here to learn!
As to my code, here is the thread with the problems I had and how I fixed them....
I am still tinkering around the edges and I expect a final version to be about a week away. It is mostly getting it all the way I want it now!