Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apple TV Remote NEC repeat signal #364

Closed
MarleyRobert opened this issue Nov 26, 2017 · 15 comments
Closed

Apple TV Remote NEC repeat signal #364

MarleyRobert opened this issue Nov 26, 2017 · 15 comments

Comments

@MarleyRobert
Copy link

hi there (peace),

I want to control my AppleTV but I have a problem. There is a Button which, when I press it once, sends the code 77E1C097 (32 bits) twice. When I press the button twice, i receive the same code four times. But there is another funtion of the button I want to use. For this one I need to hold the button for about 1-2 sec. So again, I get the same code twice and after that I get the NEC(repeat) code

screen shot 2017-11-26 at 17 24 51

does anybody of you know how I can send the NEC repeat signal or does anyone know a way around this problem?

best regards,
michel

@crankyoldgit
Copy link
Owner

All you need to do is specify the number of repeats when calling sendNEC().
How to do that is described in the code here.

From your example, if you wanted to transmit that sequence of a NEC 77E1A097 message and three (3) NEC repeat messages, you'd make the following call:
sendNEC(0x77E1A097, 32, 3);

@crankyoldgit
Copy link
Owner

Friendly ping. How did it work for you?

@MarleyRobert
Copy link
Author

Hey crankyoldgit at first thanks for your help, I really appreciate that!

Unfortunately I don't have much time to work on my project at the moment, but I tested it right now and it doesn't work. When I use the remote, to turn the AppleTV off, LED light is off as long as I push the button. But if I use my board to transmit the code, the light goes off and immediately on. Like it would only send one signal.
In my ino my timer is a bit fucked, like delay doesn't really work like it should. It doesn't delay. Could that be a part of this problem?

@crankyoldgit
Copy link
Owner

I'm curious, how does the delay not work like it should?! (Feel free to post your .ino here, Just use the "Insert code" selection when you do so to keep it formatted.)

I used to have an old Gen 1 Apple TV, I know the "hold" button thing. That used to be held down for seconds or so at a time. If that's what you are trying to reproduce, just be aware that the each message (i.e. the initial and each "repeat" command) is only about roughly 100 milliseconds. So, if say you wanted to emulate holding the button down for 5 seconds, you'd need 5000/100 = 50 or so repeats.

e.g.
sendNEC(code_you_want_to_send, 32, 50);
That will send a single "code_you_want_to_send, plus 50 repeat codes.

The command itself does all of it's delay's internally. i.e. that command will take about 5 seconds to complete, hopefully.

If however, what you are saying is your ESP isn't behaving correctly when doing delay()s, then yeah, that's probably a big issue.

@MarleyRobert
Copy link
Author

I will give you a quick overview over the project.

I want to control my living room with amazon echo, so far so good. I can switch my TV on/off and also my music system, just with saying "Alexa, turn my TV/music system on/off" (On works with the AppleTV, but I only tried six repeat codes to turn it off. 'cause my universal remote used six). For that I dont really need the delay() function. But I also want to make a advanced command, like YouTube. When I say "Alexa, turn YouTube on." my TV, music system and AppleTV should start, after a short delay my TV/music system should switch to the right inputs and the AppleTV should go two apps to the right and confirm so YouTube get started.
Unfortunately all codes are send nearly the same time, so my TV, music system and AppleTV are booting and they can't process the other commands.
I tried a few things, like make a own function called pause() to make my way around delay() and a few loops with millis() and other stuff to keep the board busy, but after a specific time the board starts to reboot.

void pause(int ms) { for (int i = 0; i < ms; i++) { delayMicroseconds(1000); } }

`Serial.println("Start");

Start = millis();

do
{
if (millis() - Start >= 10000)
{
Serial.println("10s");
nr = 2;
}
}while(nr == 1);`

ino:

`
#include <ESP8266WiFi.h>
#include <RCSwitch.h>
#include "fauxmoESP.h"

#include <IRremoteESP8266.h> //by Ken Shirriff (C) NEU
#include <IRsend.h>

#define WIFI_SSID "Mr. NiceGuy (.Y.)"
#define WIFI_PASS "*************"

fauxmoESP alexawifi;
RCSwitch mySwitch = RCSwitch();

IRsend IRLED(4); // IRLED angeschlossen am D2 Pin (GPIO4) - NEU

unsigned long Start;
unsigned long previousMillis = 0;
unsigned long interval = 50;
int value = 0;

void wifiSetup() {

// -----------------------------------------------------------------------------
// WLAN SETUP
// -----------------------------------------------------------------------------

WiFi.mode(WIFI_STA);

Serial.printf("Verbindungs zu %s wird aufgebaut ", WIFI_SSID);

WiFi.begin(WIFI_SSID, WIFI_PASS);

while (WiFi.status() != WL_CONNECTED) 
{
    Serial.print(">");
    delay(100);
} 
Serial.println("");
Serial.printf("Verbunden! SSID: %s, IP Adresse: %s\n", WiFi.SSID().c_str(), WiFi.localIP().toString().c_str());

}

void pause(int ms)
{
for (int i = 0; i < ms; i++)
{
delayMicroseconds(1000);
}
}

void anfrage(uint8_t device_id, const char * device_name, bool state)
{
Serial.print("Gerät: ");
Serial.println(device_name);
Serial.print("Status: ");

if (state) //Geräte anschalten - devices turn on
{
if(device_id == 0) //AppleTV
{
Serial.println("AN");
IRLED.sendNEC(0x77E12080, 32); //AppleTV an
delay(50);
}

else if (device_id == 1)      //Fernseher - TV
{ 
  Serial.println("AN");
  IRLED.sendRC6(0x1000C, 20);   //Fernseher an - on
  delay(50);
}

else if (device_id == 2)      //Anlage - music system
{ 
  Serial.println("AN");
  IRLED.sendNEC(0x10E03FC, 32);   //Anlage an
  delay(50);
}

else if (device_id == 3)      //YouTube
{ 
  Serial.println("AN");
  IRLED.sendRC6(0x1000C, 20);   //Fernseher an - TV on 
  Serial.println("TV an");
  delay(60);
  IRLED.sendNEC(0x10E03FC, 32);   //Anlage an - music system on
  Serial.println("Anlage An");
  delay(60);
  IRLED.sendNEC(0x77E1FA80, 32);   //AppleTV an - on
  Serial.println(millis());
  delay(1500);
  Serial.println(millis());
  
  for(int i = 0; i < 2; i++)
  {
    IRLED.sendNEC(0x77E16080, 32); //Apple TV rechts - right
    Serial.println("rechts");
    delay(60);
  }
  
  IRLED.sendNEC(0x77E1A080, 32);   //Apple TV Bestätigen - ok
  Serial.println("Ok");
  delay(4000);
  IRLED.sendRC5(0x839, 12);   //Fernseher auf AppleTV Eingang - TV input on AppleTV
  Serial.println("AppleTV EIngang");
  delay(60);
  IRLED.sendNEC(0x10E0BF4, 32);   //Anlage auf DVD Eingang - music system input on DVD
  Serial.println("DVD EIngang");
  delay(60);
}

else if (device_id == 4)      //Netflix
{ 
  Serial.println("AN");
  IRLED.sendRC6(0x1000C, 20);   //TV an
  delay(500);
  IRLED.sendNEC(0x10E03FC, 32);   //Anlage an
  delay(500);
  IRLED.sendNEC(0x77E1A080, 32);   //Apple TV an
  delay(5000);
  IRLED.sendNEC(0x77E13A80, 32);   //Apple TV Bestätigen
  delay(1000);
  IRLED.sendRC5(0x84C, 12);   //TV auf AppleTV Eingang
  delay(500);
  IRLED.sendNEC(0x10E23DC, 32);   //Anlage auf DVD Eingang
  delay(500);
}

else if (device_id == 5)      //PlayStation Modus
{ 
  Serial.println("AN");
  IRLED.sendRC6(0x1000C, 20);   //TV an
  delay(500);
  IRLED.sendNEC(0x10E03FC, 32);   //Anlage an
  delay(5000);
  IRLED.sendRC5(0xC4, 12);   //TV auf PS4 Eingang
  delay(500);
  IRLED.sendNEC(0x10E0BF4, 32);   //Anlage auf DVD Eingang
  delay(500);
}

else if (device_id == 6)      //Musik
{ 
  IRLED.sendNEC(0x10E23DC, 32);   //Anlage auf CD/Bluetooht
  delay(50);
}

else if (device_id == 7)      //Alles
{ 
  Serial.println("Alles AN");
  IRLED.sendNEC(0x10E03FC, 32);   //Anlage an
  delay(50);
  IRLED.sendRC6(0x1000C, 20);   //TV an
  delay(50);
}

}

else //Geräte Ausschalten
{

if(device_id == 0)            //Apple TV
{ 
  Serial.println("AUS");
  IRLED.sendNEC(0x77E1A080, 32, 6);   //Apple TV aus - off
  delay(50);
}

else if (device_id == 1)      //Fernseher
{ 
  Serial.println("AUS");
  IRLED.sendRC6(0x1000C, 20);   //Fernseher aus - TV off
  delay(50);
}

else if (device_id == 2)      //Anlage
{ 
  Serial.println("AUS");
  IRLED.sendNEC(0x10EF906, 32);   //Anlage aus
  delay(50);
}

else if (device_id == 3)      //Youtube
{ 
  Serial.println("AUS");
  IRLED.sendRC6(0x1000C, 20);   //TV aus
  delay(500);
  IRLED.sendNEC(0x10EF906, 32);   //Anlage aus
  delay(500);
  IRLED.sendNEC(0x77E1C080, 32);   //AppleTV Home
  delay(500);
  
  for(int i = 0; i < 3; i++)
  {
    IRLED.sendNEC(0x77E19080, 32); //Apple TV links - left
    delay(500);
  }

  //IRLED.sendNEC(0x77E1A080, 32);   //Apple TV aus
  //delay(500);
}

else if (device_id == 4)      //Netflix
{ 
  Serial.println("AUS");
  IRLED.sendRC5(0x84C, 12);   //TV aus
  delay(500);
  IRLED.sendRC5(0x84C, 12);   //Anlage aus
  delay(500);
  IRLED.sendNEC(0x77E1C080, 32);   //AppleTV Home
  delay(500);
  //IRLED.sendNEC(0x77E1A080, 32);   //Apple TV aus
  //delay(50);
}

else if (device_id == 5)      //Zocker Modus
{ 
  Serial.println("AUS");
  IRLED.sendRC6(0x1000C, 20);   //TV aus
  delay(500);
  IRLED.sendNEC(0x10EF906, 32);   //Anlage aus
  delay(500);
}

else if (device_id == 6)      //Music
{ 
  Serial.println("AUS");
  IRLED.sendNEC(0x10EF906, 32);   //Anlage aus
  delay(50);
}

else if (device_id == 7)      //Alles
{ 
  Serial.println("Alles AUS");
  IRLED.sendNEC(0x10EF906, 32);   //Anlage aus
  delay(50);
  IRLED.sendRC6(0x1000C, 20);   //TV aus
  delay(50);
}

}
}

void geraete(){

alexawifi.addDevice("Apple TV");      //ID 0    
alexawifi.addDevice("Fernseher");     //ID 1
alexawifi.addDevice("Anlage");        //ID 2
alexawifi.addDevice("YouTube");       //ID 3
alexawifi.addDevice("Netlix");        //ID 4
alexawifi.addDevice("PlayStation Modus");  //ID 5
alexawifi.addDevice("Musik");         //ID 6
alexawifi.addDevice("Alles");         //ID 7



alexawifi.onMessage(anfrage);

}

void setup() {

Serial.begin(115200);
Serial.println("Nach dem Verbinden, sage 'Alexa, schalte <Gerät> an' oder 'aus'");

mySwitch.enableTransmit(5);

IRLED.begin(); // NEU

wifiSetup();
geraete();

}

void loop()
{
alexawifi.handle();

// if (millis() - previousMillis > interval)
// {
// previousMillis = millis();
// value += 1;
// }
}`

@crankyoldgit
Copy link
Owner

FYI, you can use the https://github.com/markszabo/IRremoteESP8266/blob/master/examples/IRMQTTServer/IRMQTTServer.ino example code and something like https://home-assistant.io/ to do automation and combined with Amazon Alexa. I do it and something similar, for example here: https://github.com/crankyoldgit/Home-AssistantConfig/blob/master/scripts.yaml

Now, to your script. Unless you have a reason, don't use delayMicroseconds(), Especially for long periods of time. The ESP8266 has a watch dog timer(WDT), it resets the ESP if it isn't "feed" every second. Normal delay() and yield() calls will reset(feed) the watch dog timer. That should hopefully stop your rebooting problem. delayMicroseconds() does NOT feed the timer, using it for long gaps will cause the device to reboot, you should only use it for very fine sub-millisecond gaps. In short, don't use your pause() routine. ;-)

Next, I notice you've got some delay(50);s in there for gaps between commands. You really need much larger gaps. Try delay(500); for a half-second delay. Most typical IR commands have about 50-100 millisecond gaps between them for full on repeating. Sending different command too close may cause a device to miss/ignore it. That said, if it works for you, fine. ;-) I've personally found 0.5-2.0 seconds is required for some devices to switch modes etc.

I'm not sure what is going in you main loop() function, but just in case alexawifi.handle(); doesn't feed the WDT, add a delay(10); in there, it's a small delay of 10 milliseconds, but it will reduce power and feed the WDT too.

Hope that helps.

@MarleyRobert
Copy link
Author

I'm a bit busy at the moment with my study, so I don't have the time to make something complete new. But I will definitely give it a go when I get the time! This is my first project and I have big goals for my apartment :D
In the command "YouTube" I used some outputs to see if dealy does delay things, but even the delay(4000) doesn't delay for 4 sec. Everything is printed right away, even "AppleTV EIngang". Do you think when I change the other delays to 500 or more and if I put a delay(10) in my loop, I will get rid of this delay problem?
I'm at the uni and will be back home at the evening, then I will try your suggestions.

`else if (device_id == 3) //YouTube
{
Serial.println("AN");
IRLED.sendRC6(0x1000C, 20); //Fernseher an - TV on
Serial.println("TV an");
delay(60);
IRLED.sendNEC(0x10E03FC, 32); //Anlage an - music system on
Serial.println("Anlage An");
delay(60);
IRLED.sendNEC(0x77E1FA80, 32); //AppleTV an - on
Serial.println(millis());
delay(1500);
Serial.println(millis());

for(int i = 0; i < 2; i++)
{
IRLED.sendNEC(0x77E16080, 32); //Apple TV rechts - right
Serial.println("rechts");
delay(60);
}

IRLED.sendNEC(0x77E1A080, 32); //Apple TV Bestätigen - ok
Serial.println("Ok");
delay(4000); //<----------------------------------------------
IRLED.sendRC5(0x839, 12); //Fernseher auf AppleTV Eingang - TV input on AppleTV
Serial.println("AppleTV EIngang"); //<---------------------------------------------------
delay(60);
IRLED.sendNEC(0x10E0BF4, 32); //Anlage auf DVD Eingang - music system input on DVD
Serial.println("DVD EIngang");
delay(60);
}`

@MarleyRobert
Copy link
Author

I tried a delay(10) in my loop and the board doesn't like it (reboot).
I set all of the delay()s >500, but this doesn't help either. And I tried to send more repeats (50), but the light of the AppleTV indicates a signal which is a bit longer than before, but also very short. So I tried here also some bigger numbers and the result is that the board reboots.
So I think the timer isn't working like it should, it doesn't use the real time. It runs way faster then the calibrated time.

@crankyoldgit
Copy link
Owner

Okay, what you describe sounds very weird and bad. I think you need to go back to basics, try loading the standard blink.ino example code. i.e. turns an led on and off every 1-2 seconds to so.
If that doesn't work (i.e. delay() is busted) then you have a fundamental problem. i.e. Arduino IDE/Board Config is badly wrong or outdated/etc, or your ESP8266 &/or circuit is faulty.

Without your exact code to download from somewhere (i.e. github/pastebin/etc) I can't help you further.

Assuming it (blink) does work, then work your way forward adding in libraries and your code bit by bit to find out what is broken. A long shot, but get rid of or rename your pause() function, just in case it is over-ridding a built in function. I doubt that will fix it, but shrug.

In order for this (IR) library to function correctly, you are going to need a working delay() function. If the chip is faulty, it's not worth wasting your time trying to code around it. Get a new one.

@MarleyRobert
Copy link
Author

When I get the time, I will start from zero and work my way up. It's very frustrating and I can't leave that alone, so I think I will probably try to start with it tonight :D
But again, thanks for your support! I will keep you up to date with my progress (peace).

@MarleyRobert
Copy link
Author

MarleyRobert commented Dec 5, 2017

Thanks crankyoldgi for your help, I really appreciate that you took some time to help me! I finally found my problem and a way around it. It was a function called onMessage in the Library above. I just copy the information I need out of it and continue without it.

`#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <ESP8266WiFi.h>

#include "fauxmoESP.h"

fauxmoESP fauxmo;

bool device_value;
unsigned char device_code;
char device_title;
int doSomething = 0;
IRsend irsend(4);

#define WIFI_SSID "Mr. NiceGuy (.Y.)"
#define WIFI_PASS "************"

void setup()
{
irsend.begin();
Serial.begin(115200);

wifiSetup();
fauxmo.enable(true);
devices();
}

void loop()
{
fauxmo.handle();

if (doSomething == 1)
{
request(device_code, device_value);
}
static unsigned long last = millis();
if (millis() - last > 5000) {
last = millis();
Serial.printf("[MAIN] Free heap: %d bytes\n", ESP.getFreeHeap());
}

}

void MusicTest()
{
Serial.println("Anlage AN");
irsend.sendNEC(0x10E03FC, 32);
delay(4000);
Serial.println("Anlage Eingang CD");
irsend.sendNEC(0x10E23DC, 32);
delay(10000);
Serial.println("Anlage AUS");
irsend.sendNEC(0x10EF906, 32);
}

void request(unsigned char device_code, bool device_value)
{
if (device_value)
{
if(device_code == 0)
{
MusicTest();
doSomething = 0;
}
}
}

void wifiSetup()
{

// ----------
// WLAN SETUP
// ----------

WiFi.mode(WIFI_STA);

Serial.printf("Verbindungs zu %s wird aufgebaut ", WIFI_SSID);

WiFi.begin(WIFI_SSID, WIFI_PASS);

while (WiFi.status() != WL_CONNECTED) 
{
    Serial.print(">");
    delay(100);
}
 
Serial.println("");
Serial.printf("Verbunden! SSID: %s, IP Adresse: %s\n", WiFi.SSID().c_str(), WiFi.localIP().toString().c_str());

}

void devices()
{
fauxmo.addDevice("Test"); //ID 0

fauxmo.onMessage(copy);
}

void copy(uint8_t device_id, const char * device_name, bool state)
{
device_value = state;
device_code = device_id;
doSomething = 1;
}`

@crankyoldgit
Copy link
Owner

crankyoldgit commented Dec 5, 2017

@MarleyRobert Um, you may now want to change your WIFI password. ;-)

e.g. #define WIFI_PASS "MbdWPn!420*"

But I'm sure you deliberately randomised it before posting to trick others. Nudge Nudge, ;-) ;-)

It seems everything is sorted now, so I'm going to close this issue. If you don't believe so, please update it and we can re-open. (plus closing it will make that password less obvious.)

@MarleyRobert
Copy link
Author

What's up @crankyoldgit (peace)
Just a quick question. When u say most devices need 0.5-2sec gaps between the signals, u mean that the devices need the time so read/process the signals or does the the function IRsend need the time to fully send the signal?

@crankyoldgit
Copy link
Owner

@MarleyRobert The former. IRsend doesn't need any time between sending signals. It doesn't care.
Some protocols require/expect a gap between messages so that end points know they are not receiving a mixed signal/noise etc. That's typically 40+ms or so. However, some devices do take time to switch modes etc, or action commands etc. or have duplicate message/button press detection etc.
One caveat, there is no locking in the library to stop you sending two overlapping signals. i.e. It is possible that you can send a message before another one is finished sending. Extremely unlikely, but the is no protection in the library for that. That's up to the caller of the library.

@crankyoldgit
Copy link
Owner

Oh and to be clear, most protocols this library supports sending include the 'inter-message' gap per protocol at the end of the active part of sending. You don't need to code for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants