Ergebnis 1 bis 5 von 5

Thema: [Projekt] ESP8266 Funk-IR Controller

  1. #1
    střelec

    Moderator

    Avatar von War-10-ck
    Registriert seit
    Jul 2013
    Ort
    Schießstand
    Beiträge
    4.760
    ngb:news Artikel
    2

    [Projekt] ESP8266 Funk-IR Controller

    Projekt
    Der ESP8266 ist ein toller Chip um kleinere Home-Automation Projekte umzusetzen. Dank vieler vieler Anleitungen im Netz ist das auch nicht sonderlich schwer. Da ich in so gut wie jedem Raum zuhause eine Alexa stehen habe und diese auch täglich nutze stört es mich immer mehr wenn ich einzelne Geräte nicht steuern kann. Zudem sind mir die WLAN Steckdosen mit ca. 30€ pro Stück auch recht teuer.
    Ziel ist es also mittels des ESP sowohl Funksteckdosen wie auch meinen Fernseher sowie alle weiteren IR-fähigen Geräte über mein WLAN zu steuern. Zuanfang erst einmal per Web-Interface. Als zweiten Schritt dann per App und als letztes ggf. noch über einen eigenen Alexa Skill.

    Bauteile
    • 1x WEMOS D1 Mini ESP8266-12
    • 1x FS1000A (Funk Sender)
    • 1x RF-5V (Funk Receiver)
    • 1x TSOP 4838 (IR Receiver)
    • 1x OLED Display SDD1306
    • 2x LD271 (IR Sender)
    • 2x Taster
    • 2x Schalter
    • 1x Widerstand 100k
    • 2x Widerstand 10k
    • 1x Widerstand 1k
    • 1x Widerstand 7 Ohm (hier zweimal 15 Ohm parallel)
    • 1x BC327-40 PNP Transistor
    • 2x 100nF Elko
    • 1x 10u Kondensator
    • 1x 1N4148 Diode


    Funktionsumfang
    • Senden von IR Signalen mittels HTTP GET Request
    • Eine interne IR Diode sendet direkt nach vorne, eine alternative Diode kann per USB angeschlossen werden
    • Senden von 433MHz Funksignalen mittels HTTP GET Request
    • Empfangen und Anzeigen von IR Signalen auf dem OLED Display
    • Empfangen und Anzeigen von Funk Signalen auf dem OLED Display
    • Externer Reset
    • Taster um die aktuelle IP-Adresse auf dem OLED Display anzuzeigen
    • Der Display schaltet sich nach einer Minute aus, nachdem etwas angezeigt wurde



    Schaltplan
    Der Aufbau der Schaltung ist nicht sonderlich komplex. Ich war allerdings zu faul mich wirklich mit den Programmen zu beschäftigen um schicke Schaltpläne am PC zu erstellen, eine Skizze als Bild wirds aber auch tun denke ich.

    Spoiler: 



    Zuanfang habe ich noch versucht das Ganze mit dem ESP-01 Modul umzusetzen. Möchte man alles auf die wirklichen Grundfunktionen beschränken wäre dies auch ohne Weiteres möglich gewesen. Da ich aber am Ende noch deutlich mehr GPIOs benötigt habe hab ich kurzerhand noch einen ESP-12 bestellt, mit dem man um einiges flexibler ist. Das tolle am ESP12 ist, dass er einen 5V Eingang hat den man direkt per USB speisen kann und einen 3,3V ausgang. Damit spart man sich einen zusätzlichen Spannungswandler. Die beiden Funkmodule laufen mit 5V, der Rest der Schaltung mit 3,3V.





    Sketch

    Vieles hab ich mir zusammen kopiert, bzw. die Beispiele der jeweiligen Bibliotheken benutzt und sie dann auf meine Bedürfnisse angepasst. Ich bin alles andere als ein C / C++ Experte, bei Fragen versuch ich aber gerne so gut wie möglich zu erklären warum ich was wie mache.

    Spoiler: 

    Code (C++):
    1. #ifndef UNIT_TEST
    2. #include <Arduino.h>
    3. #endif
    4. #include <ESP8266WiFi.h>
    5. #include <ESP8266WebServer.h>
    6. #include <ESP8266mDNS.h>
    7. #include <IRremoteESP8266.h>
    8. #include <IRsend.h>
    9. #include <IRrecv.h>
    10. #include <IRutils.h>
    11. #include <WiFiClient.h>
    12. #include <RCSwitch.h>
    13. #include <DNSServer.h>
    14. #include <WiFiManager.h>
    15. #include "SSD1306.h"
    16. #if DECODE_AC
    17. #include <ir_Daikin.h>
    18. #include <ir_Fujitsu.h>
    19. #include <ir_Gree.h>
    20. #include <ir_Haier.h>
    21. #include <ir_Kelvinator.h>
    22. #include <ir_Midea.h>
    23. #include <ir_Toshiba.h>
    24. #endif  // DECODE_AC
    25.  
    26. const char* wifihostname = "ESP";
    27. #define IR_SENDER D6
    28. #define IR_RECEIVER D7
    29. #define RADIO_SENDER D1
    30. #define RADIO_RECEIVER D2
    31. #define SHOW_IP_BUTTON D8
    32.  
    33. #define CAPTURE_BUFFER_SIZE 1024
    34. #define MIN_UNKNOWN_SIZE 12
    35. #define DISPLAY_CLEAR_TIMEOUT 60000
    36.  
    37. MDNSResponder mdns;
    38. ESP8266WebServer server(80);
    39. WiFiManager wifiManager;
    40. RCSwitch mySwitch_send = RCSwitch();
    41. RCSwitch mySwitch_receive = RCSwitch();
    42. IRsend irsend(IR_SENDER, true);
    43. decode_results results;
    44.  
    45. #if DECODE_AC
    46. #define TIMEOUT 50U
    47. #else
    48. #define TIMEOUT 15U
    49. #endif
    50. IRrecv irrecv(IR_RECEIVER, CAPTURE_BUFFER_SIZE, TIMEOUT, true);
    51.  
    52. SSD1306  display(0x3c, D3, D5);
    53. int showIpButtonState = 0;
    54.  
    55. long timeSinceLastDisplaySwitch = 0;
    56.  
    57. void handleRoot() {
    58.   server.send(200, "text/html",
    59.               "<html>" \
    60.                 "<head><title>ESP Home-Automation Center</title></head>" \
    61.                 "<body>" \
    62.                   "<h1>ESP Home-Automation Control</h1>" \
    63.                   "<hr>" \
    64.                   "<h3>TV</h3>" \
    65.                   "<p><a href="ir?code=551489775">TV ON/OFF</a></p>" \
    66.                  
    67.                   "<hr>" \
    68.                   "<h3>Funksteckdose A</h3>" \
    69.                   "<p><a href=radio?code=000000FFFF0F>Funksteckdose A ON</a></p>" \
    70.                   "<p><a href=radio?code=000000FFFFF0>Funksteckdose A OFF</a></p>" \
    71.                   "<hr>" \
    72.                   "<h3>Funksteckdose B</h3>" \
    73.                   "<p><a href=radio?code=00000F0FFF0F>Funksteckdose B ON</a></p>" \
    74.                   "<p><a href=radio?code=00000F0FFFF0>Funksteckdose B OFF</a></p>" \
    75.                   "<hr>" \
    76.                   "<h3>Funksteckdose C</h3>" \
    77.                   "<p><a href=radio?code=00000FF0FF0F>Funksteckdose C ON</a></p>" \
    78.                   "<p><a href=radio?code=00000FF0FFF0>Funksteckdose C OFF</a></p>" \
    79.                   "<hr>" \
    80.                 "</body>" \
    81.               "</html>");
    82. }
    83.  
    84. void displayRadioCode(unsigned long decimal, unsigned int length){
    85.   const char* b = dec2binWzerofill(decimal, length);
    86.   String displayText(bin2tristate( b));
    87.   display.clear();
    88.   display.drawString(0, 0, "Radio-Code");
    89.   display.drawString(0, 16, displayText);
    90.   display.display();
    91.   setTimeSinceLastDisplaySwitch();
    92. }
    93.  
    94. void displayIrCode() {
    95.   if (irrecv.decode(&results)) {
    96.     display.clear();
    97.     display.drawString(0, 0, "IR-Code");
    98.     display.drawString(0, 16, hex2dec(getIrCode(&results)));
    99.     display.display();
    100.     setTimeSinceLastDisplaySwitch();
    101.   }
    102. }
    103.  
    104. String hex2dec(String hex) {
    105.     unsigned long result = 0;
    106.     for (int i=0; i<hex.length(); i++) {
    107.         if (hex[i]>=48 && hex[i]<=57)
    108.         {
    109.             result += (hex[i]-48)*pow(16,hex.length()-i-1);
    110.         } else if (hex[i]>=65 && hex[i]<=70) {
    111.             result += (hex[i]-55)*pow(16,hex.length( )-i-1);
    112.         } else if (hex[i]>=97 && hex[i]<=102) {
    113.             result += (hex[i]-87)*pow(16,hex.length()-i-1);
    114.         }
    115.     }
    116.     return uint64ToString(result);
    117. }
    118.  
    119. String getIrCode(const decode_results *results) {
    120.   String displayText = "";
    121.   if (hasACState(results->decode_type)) {
    122.     #if DECODE_AC
    123.           for (uint16_t i = 0; results->bits > i * 8; i++) {
    124.             if (results->state[i] < 0x10)  displayText += "0";
    125.               displayText += uint64ToString(results->state[i], 16);
    126.           }
    127.     #endif  // DECODE_AC
    128.   } else {
    129.     displayText += uint64ToString(results->value, 16);
    130.   }
    131.   return displayText;
    132. }
    133.  
    134. void handleIr() {
    135.   for (uint8_t i = 0; i < server.args(); i++) {
    136.     if (server.argName(i) == "code") {
    137.       uint32_t code = strtoul(server.arg(i).c_str(), NULL, 10);
    138. #if SEND_NEC
    139.       irsend.sendNEC(code, 32);
    140. #endif  // SEND_NEC
    141.     }
    142.   }
    143.   handleRoot();
    144. }
    145.  
    146. void handleRadio() {
    147.   for (uint8_t i = 0; i < server.args(); i++) {
    148.     if (server.argName(i) == "code") {
    149.       const char* code = server.arg(i).c_str();
    150.       mySwitch_receive.disableReceive();
    151.       mySwitch_send.sendTriState(server.arg(i).c_str());
    152.       delay(50);
    153.       mySwitch_receive.enableReceive(RADIO_RECEIVER);
    154.     }
    155.   }
    156.   handleRoot();
    157. }
    158.  
    159. void handleNotFound() {
    160.   String message = "File Not Found\n\n";
    161.   message += "URI: ";
    162.   message += server.uri();
    163.   message += "\nMethod: ";
    164.   message += (server.method() == HTTP_GET)?"GET":"POST";
    165.   message += "\nArguments: ";
    166.   message += server.args();
    167.   message += "\n";
    168.   for (uint8_t i = 0; i < server.args(); i++)
    169.     message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
    170.   server.send(404, "text/plain", message);
    171. }
    172.  
    173. static const char* bin2tristate(const char* bin) {
    174.   static char returnValue[50];
    175.   int pos = 0;
    176.   int pos2 = 0;
    177.   while (bin[pos]!='\0' && bin[pos+1]!='\0') {
    178.     if (bin[pos]=='0' && bin[pos+1]=='0') {
    179.       returnValue[pos2] = '0';
    180.     } else if (bin[pos]=='1' && bin[pos+1]=='1') {
    181.       returnValue[pos2] = '1';
    182.     } else if (bin[pos]=='0' && bin[pos+1]=='1') {
    183.       returnValue[pos2] = 'F';
    184.     } else {
    185.       return "not applicable";
    186.     }
    187.     pos = pos+2;
    188.     pos2++;
    189.   }
    190.   returnValue[pos2] = '\0';
    191.   return returnValue;
    192. }
    193.  
    194. static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength) {
    195.   static char bin[64];
    196.   unsigned int i=0;
    197.  
    198.   while (Dec > 0) {
    199.     bin[32+i++] = ((Dec & 1) > 0) ? '1' : '0';
    200.     Dec = Dec >> 1;
    201.   }
    202.  
    203.   for (unsigned int j = 0; j< bitLength; j++) {
    204.     if (j >= bitLength - i) {
    205.       bin[j] = bin[ 31 + i - (j - (bitLength - i)) ];
    206.     } else {
    207.       bin[j] = '0';
    208.     }
    209.   }
    210.   bin[bitLength] = '\0';
    211.  
    212.   return bin;
    213. }
    214.  
    215. void checkShowIp() {
    216.   showIpButtonState = digitalRead(SHOW_IP_BUTTON);
    217.  
    218.   if (showIpButtonState == HIGH) {
    219.     display.clear();
    220.     display.drawString(0, 0, "IP Address");
    221.     display.drawString(0, 16, WiFi.localIP().toString());
    222.     display.display();
    223.     setTimeSinceLastDisplaySwitch();
    224.   }
    225. }
    226.  
    227. void checkDisplayTimeout() {  
    228.   if (millis() - timeSinceLastDisplaySwitch > DISPLAY_CLEAR_TIMEOUT) {
    229.     display.clear();
    230.     display.display();
    231.   }
    232. }
    233.  
    234. void setTimeSinceLastDisplaySwitch() {
    235.   timeSinceLastDisplaySwitch = millis();
    236. }
    237.  
    238. void setup(void) {
    239.   // IR
    240.   irsend.begin();
    241.   digitalWrite(D6, HIGH); // as the pin works inverted after the pnp transistor set it to HIGH to switch off the ir led by default
    242.   #if DECODE_HASH  
    243.   irrecv.setUnknownThreshold(MIN_UNKNOWN_SIZE);
    244.   #endif  // DECODE_HASH
    245.   irrecv.enableIRIn();  // Start the receiver
    246.  
    247.   // RADIO
    248.   mySwitch_send.enableTransmit(RADIO_SENDER);
    249.   mySwitch_send.setProtocol(1);
    250.   mySwitch_send.setPulseLength(187);
    251.   mySwitch_receive.enableReceive(RADIO_RECEIVER);
    252.  
    253.   // DISPLAY
    254.   display.init();
    255.   display.flipScreenVertically();
    256.   display.setFont(ArialMT_Plain_16);
    257.   display.setTextAlignment(TEXT_ALIGN_LEFT);
    258.  
    259.   //Serial.begin(115200);
    260.  
    261.   // WIFI
    262.   wifiManager.setAPStaticIPConfig(IPAddress(192,168,0,125), IPAddress(192,168,0,1), IPAddress(255,255,255,0));
    263.   wifiManager.autoConnect("ESP-AP", "1234");
    264.   while (WiFi.status() != WL_CONNECTED) {
    265.     delay(500);
    266.     //Serial.print(".");
    267.   }
    268.   //if (mdns.begin("esp8266", WiFi.localIP())) {
    269.     //Serial.println("MDNS responder started");
    270.   //}
    271.  
    272.   // SERVER
    273.   server.on("/", handleRoot);
    274.   server.on("/ir", handleIr);
    275.   server.on("/radio", handleRadio);
    276.   server.on("/inline", [](){
    277.     server.send(200, "text/plain", "this works as well");
    278.   });
    279.   server.onNotFound(handleNotFound);
    280.   server.begin();
    281.   //Serial.println("HTTP server started");
    282.  
    283.   // IP BUTTON
    284.   pinMode(SHOW_IP_BUTTON, INPUT);
    285. }
    286.  
    287. void loop(void) {
    288.   server.handleClient();
    289.   if (mySwitch_receive.available()) {
    290.     displayRadioCode(mySwitch_receive.getReceivedValue(), mySwitch_receive.getReceivedBitlength());
    291.     mySwitch_receive.resetAvailable();
    292.   }
    293.   displayIrCode();
    294.   checkShowIp();
    295.   checkDisplayTimeout();
    296.   delay(50);
    297. }


    Gehäuse
    Das Gehäuse habe ich mit einem 3D Drucker hergestellt; bzw. mein Bruder. Das ganze ist nicht wunderschön aber zweckdienlich. Der Deckel lässt sich aufklappen für den Fall, dass man den ESP noch einmal herausnehmen und neu Flashen möchte.

    Spoiler: 











    Umsetzung











    Problem
    Da mir am Ende dann die Lust gefehlt hat rauszufinden woran genau es liegt und alles schon verlötet war habe ich es als gegeben hingenommen, dass der ESP nach dem Power-ON erst funktioniert nachdem er noch einmal resettet wurde. Stört mich nicht solange man weiß, dass es nötig ist. Wenn jemand eine Idee hat bitte gerne kommentieren.
    Für diesen Beitrag bedanken sich theSplit, phre4k, Ungesund, DandG, LadyRavenous
    Geändert von War-10-ck (03.04.18 um 17:38 Uhr)

  2. #2
    Mitglied Avatar von phre4k
    Registriert seit
    Mar 2015
    Beiträge
    5.478
    ngb:news Artikel
    4

    Re: [Projekt] ESP8266 Funk-IR Controller

    Geil, das Projekt habe ich mir schon lange vorgenommen und jetzt macht einer meine Arbeit
    *mit Linux wäre das natürlich nicht passiert™
    Arguing that you don't care about the right to privacy because you have nothing to hide is no different than saying you don't care about free speech because you have nothing to say. – Edward Snowden
    tilde.fun – dein kostenloser Linux-Account in der Cloud | Inoffizielle ngb-Telegram-Gruppe
    GCM/S/TW d s+:- a-----? C++$ UL+++$ P-- L+++ E---- W++++ !N ?K w- M-- !P[A-Z] Y++ PGP R* tv-- b++>++++ DI++\:\( G+ e+>++++ h*

  3. #3
    střelec

    Moderator

    (Threadstarter)

    Avatar von War-10-ck
    Registriert seit
    Jul 2013
    Ort
    Schießstand
    Beiträge
    4.760
    ngb:news Artikel
    2

    Re: [Projekt] ESP8266 Funk-IR Controller

    Ich seh gerade, dass ich vergessen habe den Sketch online zu stellen. Mache ich nachher wenn ich nach Hause komme. Das Ganze hat sich im Übrigen eher so entwickelt, vieles kann man bestimmt besser machen. PNP Transistor durch NPN austauschen zum Beispiel. Bei ESP01 war der PNP noch nötig da GPIO2 beim Boot auf high liegen musste, das brauchts jetzt beim ESP12 nicht mehr. Würde die Softwareseite etwas einfacher machen.

  4. #4
    Such da fuq Avatar von DandG
    Registriert seit
    Jun 2016
    Ort
    In mein Haus.
    Beiträge
    396

    Re: [Projekt] ESP8266 Funk-IR Controller

    Ist es nicht möglich, das er nach dem powerOn XYZ sek. Wartet und dann ein reset von selbst durchführt?
    Also per Software und/oder Hardware?

  5. #5
    střelec

    Moderator

    (Threadstarter)

    Avatar von War-10-ck
    Registriert seit
    Jul 2013
    Ort
    Schießstand
    Beiträge
    4.760
    ngb:news Artikel
    2

    Re: [Projekt] ESP8266 Funk-IR Controller

    Hab nochmal den Code ergänzt.
    Sicherlich könnte man das mit dem Reset irgendwie noch durch Hardware-/Softwareseitige Änderungen automatisch lösen. Denke aber bevor man da groß rumprobiert ist die Zeit besser darein investiert das eigentliche Problem zu finden. Als es bei mir noch auf dem Breadboard gesteckt hat lief es ganz wunderprächtig. Irgendwo hab ich wahrscheinlich beim Zusammenlöten einen Fehler gemacht.

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •