Ziel

Der Web-Server auf dem ESP32 wird so erweitert, dass er IR-Codes entsprechend den Alexa-Kommandos versendet.

In­halts­ver­zeich­nis

Prinzip

Hardware

Software

IR-Muster

Ausgabe der IR-Codes

Request-Handler des Web-Servers

Download

zurück


Prinzip

An einen der GPIO-Pins wird mit einem Vorwiderstand zur Strombegrenzung eine IR-LED angeschlossen. Über diese LED werden die IR-Codes ausgegeben. Sie emittiert ein 36..40 kHz-Signal, auf das die IR-Codes aufmoduliert sind.

Für mein Handy habe ich schon einmal eine Fernbedienung für meinen Metz-Fernseher programmiert (AI2 IR Xmitter Extension: Unsichtbare Kontrolle). Dort ist auch beschrieben, wie man an die benötigten Codes kommt (Aufnahme von IR-Codes).

Beim ESP32 ist es recht einfach, die Codes zu generieren. Die Grundfrequenz, hier 38 kHz, werden über PWM erzeugt. Die Modulation wird durch Veränderung des Tastverhältnisses (Duty Cicle) gesteuert. Beträgt dieser 50% wird ein Signal ausgesendet, beträgt er 0% (oder 100%, je nach Schaltung), bleibt die LED aus. Eine ausführliche Anleitung gibt es z.B. bei Elektronik-Labor: Lernende Infrarot-Fernbedienung mit ESP32.

Hardware

Die zusätzliche Hardware ist überschaubar. Ich habe eine IR-LED aus einer alten Fernbedienung ausgebaut. Solche LEDs sind überlicherweise für einen Vorwärtsstrom (Betriebsstrom) von 100 mA ausgelegt, vertragen aber im gepulsten Betrieb deutlich mehr. Die Flussspannung beträgt i.d.R. 1,3..1.5 V. Die GPIO-Pins des ESP32 liefern diesen Strom nicht. Man kann

Hardware

Es gibt im Prinzip vier Möglichkeiten die LED anzuschließen. GPIO1 ist gleichwertig mit GPIO2 und GPIO3 ist gleichwertig mit GPIO4, denn es ist egal ob der Vorwiderstand vor oder nach der LED eingebaut wird.

Bei den beiden oberen Schaltungen muss der GPIO-Pin Strom aufnehmen (Sink) bei den beiden unteren Strom liefern (Source). Bei einigen μC sind der maximale Sink- und Source-Strom unterschiedlich groß.

Software

IR-Muster

Die Muster sind eine Folge von Ein- und Auszeiten für das Trägersignal von 38 kHz in μs, beginnend mit einer Dauer für die erste Zeit, bei der das Signal eingeschaltet ist. Z.B.:

uint32_t onOffPattern[] = { 800,2400,400,1000,400,1000,400,1700,400,1700,400,1000,400,1700,400,1000,400,1000,
                            400,1700,400,1000,400,1000,400,1000,400,1700,400,1000,400,1700,400,1000,400,1700,
                            400,1700,400,1700,400,1000,400,1700,400,1000,400,1700,400 };

Das Signal beginnt mit einem 800 μs dauernden 38 kHz-Puls, gefolgt von einer Pause von 2.400 μs. Dann wieder ein 400 µs dauern Puls mit der Trägerfrequenz, usw. Im Beispiel (s. Download) sind nur die Codes für die wichtigsten Tasten der Fernbedienung hinterlegt.

Ausgabe der IR-Codes

Die Trägerfrequenz von 38 kHz wird über das LEDC-API des ESP32 erzeugt. Weitere Details findet man im ESP-IDF Programming Guide oder im technischen Referenzhandbuch des ESP32.

// Konstanten für das LEDC-Interface
const uint8_t irLedPin = 15;           // Pin an den die IR-Sende-LED angeschlossen ist
const uint16_t irPwmFrequency = 38000; // Trägerfrequenz des IR-Signals: 38kHz
const uint8_t irPwmChannel = 0;        // PWM-Channel für das PWM-Signal

void setup() {
...
   // PWM-Einstellungen für den IR-Transmitter
   ledcSetup(irPwmChannel, irPwmFrequency, 8);
   ledcAttachPin(irLedPin, irPwmChannel);
   ledcWrite(irPwmChannel, 0);  // IR-Signal Ausschalten
   
...

Die Routine zum Versenden der Codes:

// Gibt eine IR - Daten - Sequenz aus
// channel: LEDC-Kanal
// irData:enthält die Start- und Stoppzeitpunkte für die Bursts
// irDataLen: Anzahl der Datenpunkte im Array
void playIrData(uint8_t channel, uint32_t irData[], uint16_t irDataLen) {
   bool active = true;

   // über das gesamte Muster
   for (int i = 0; i < irDataLen; i++) {
      uint64_t endTime = esp_timer_get_time() + irData[i];
      if (active) {
         ledcWrite(channel, 128);    // Trägerfrequenz einschalten
         active = false;
      }
      else {
         ledcWrite(channel, 0);  // Trägerfrequenz ausschalten
         active = true;
      };
      while (esp_timer_get_time() < endTime); // Warten, bis Zeit abgelaufen ist.
   }
   ledcWrite(channel, 0); // sicherstellen, dass der IR-Sender ausgeschaltet ist
}

Request-Handler des Web-Servers

Die Request-Handler müssen die Codes gemäß der Anfrage aussenden, aber auch auf ungültige Angaben reagieren. Für das An- und Ausschalten des Fernsehers sieht das so aus.

void handleTvRequest() {
   Serial.printf("TvRequest from %s, Argument ist %s\n", server.client().remoteIP().toString().c_str(), server.arg(0).c_str());

   if (server.arg(0) == "ein" || server.arg(0) == "an" || server.arg(0) == "aus") {
      playIrData(irPwmChannel, onOffPattern, PatternSize(onOffPattern));
      server.send(200, "text/html", "fernseher " + server.arg(0) + " geschaltet.");
   }
   else
      server.send(200, "text/html", "das kommando habe ich nicht verstanden. du kannst sagen fernseher an oder fernseher aus.");
}

Die Programmwahl ist etwas komplexer:

void handleChannelRequest() {
   bool channelFound = false;
   String Text = server.arg(0);
   Serial.printf("ChannelRequest from %s, Argument ist %s\n", server.client().remoteIP().toString().c_str(), server.arg(0).c_str());
   if (server.arg(0) == "ARD" || server.arg(0) == "1.") {
      playIrData(irPwmChannel, _1Pattern, PatternSize(_1Pattern));
      delay(cmdDelay);
      playIrData(irPwmChannel, OkPattern, PatternSize(OkPattern));
      Text = "a er de";
      channelFound = true;
   }
   else if (server.arg(0) == "ZDF" || server.arg(0) == "2.") {
      playIrData(irPwmChannel, _2Pattern, PatternSize(_2Pattern));
      delay(cmdDelay);
      playIrData(irPwmChannel, OkPattern, PatternSize(OkPattern));
      Text = "z d f";
      channelFound = true;
   }
   else if (server.arg(0) == "RTL") {
      playIrData(irPwmChannel, _3Pattern, PatternSize(_3Pattern));
      delay(cmdDelay);
      playIrData(irPwmChannel, OkPattern, PatternSize(OkPattern));
      channelFound = true;
   }
   else if (server.arg(0) == "pro 7") {
      playIrData(irPwmChannel, _7Pattern, PatternSize(_7Pattern));
      channelFound = true;
   }

   // -----------------------------------------
   // ... weitere Kanal-Anfragen
   // -----------------------------------------

   if (channelFound)
      server.send(200, "text/html", "programm " + Text + "habe ich eingestellt.");
   else
      server.send(200, "text/html", "das programm " + Text + " kenne ich nicht.");
}

Im Beispiel sind nur vier Kanäle ausgeführt. Bei meinem Fernseher hat insgesamt 64 Kanäle programmiert. Deshalb wartet der Fernseher nach Empfang einer Ziffer von 1..5 darauf, ob eine weitere Ziffer folgt. Dies kann man durch das Senden von OK abkürzen (s. ARD, ZDF und RTL). Kanal 7 ist eindeutig. Weiterhin muss berücksichtigt werden, dass mehrere Angaben für das gleiche Programm erlaubt sind. (ARD und 1. für ARD). Für die Rückmeldung muss der Text aufbereitet werden. ARD wird von Alexa z.B. als ein Wort Ard ausgesprochen.

Download

Das ZIP-Archiv Alaxa-ESP32.ZIP enthält im Order 5. Web-Server mit IR-Kommandos das komplette Visual Micro Projekt für den Web-Server. Arduino-IDE-Anwender nutzen nur die .ino-Datei.

zurück