• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

[Projekt] ESP8266 Funk-IR Controller

War-10-ck

střelec
Veteran

Registriert
14 Juli 2013
Beiträge
5.952
Ort
Schießstand
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.


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. :)

[src=cpp]#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <IRrecv.h>
#include <IRutils.h>
#include <WiFiClient.h>
#include <RCSwitch.h>
#include <DNSServer.h>
#include <WiFiManager.h>
#include "SSD1306.h"
#if DECODE_AC
#include <ir_Daikin.h>
#include <ir_Fujitsu.h>
#include <ir_Gree.h>
#include <ir_Haier.h>
#include <ir_Kelvinator.h>
#include <ir_Midea.h>
#include <ir_Toshiba.h>
#endif // DECODE_AC

const char* wifihostname = "ESP";
#define IR_SENDER D6
#define IR_RECEIVER D7
#define RADIO_SENDER D1
#define RADIO_RECEIVER D2
#define SHOW_IP_BUTTON D8

#define CAPTURE_BUFFER_SIZE 1024
#define MIN_UNKNOWN_SIZE 12
#define DISPLAY_CLEAR_TIMEOUT 60000

MDNSResponder mdns;
ESP8266WebServer server(80);
WiFiManager wifiManager;
RCSwitch mySwitch_send = RCSwitch();
RCSwitch mySwitch_receive = RCSwitch();
IRsend irsend(IR_SENDER, true);
decode_results results;

#if DECODE_AC
#define TIMEOUT 50U
#else
#define TIMEOUT 15U
#endif
IRrecv irrecv(IR_RECEIVER, CAPTURE_BUFFER_SIZE, TIMEOUT, true);

SSD1306 display(0x3c, D3, D5);
int showIpButtonState = 0;

long timeSinceLastDisplaySwitch = 0;

void handleRoot() {
server.send(200, "text/html",
"<html>" \
"<head><title>ESP Home-Automation Center</title></head>" \
"<body>" \
"<h1>ESP Home-Automation Control</h1>" \
"<hr>" \
"<h3>TV</h3>" \
"<p><a href="ir?code=551489775">TV ON/OFF</a></p>" \

"<hr>" \
"<h3>Funksteckdose A</h3>" \
"<p><a href=radio?code=000000FFFF0F>Funksteckdose A ON</a></p>" \
"<p><a href=radio?code=000000FFFFF0>Funksteckdose A OFF</a></p>" \
"<hr>" \
"<h3>Funksteckdose B</h3>" \
"<p><a href=radio?code=00000F0FFF0F>Funksteckdose B ON</a></p>" \
"<p><a href=radio?code=00000F0FFFF0>Funksteckdose B OFF</a></p>" \
"<hr>" \
"<h3>Funksteckdose C</h3>" \
"<p><a href=radio?code=00000FF0FF0F>Funksteckdose C ON</a></p>" \
"<p><a href=radio?code=00000FF0FFF0>Funksteckdose C OFF</a></p>" \
"<hr>" \
"</body>" \
"</html>");
}

void displayRadioCode(unsigned long decimal, unsigned int length){
const char* b = dec2binWzerofill(decimal, length);
String displayText(bin2tristate( b));
display.clear();
display.drawString(0, 0, "Radio-Code");
display.drawString(0, 16, displayText);
display.display();
setTimeSinceLastDisplaySwitch();
}

void displayIrCode() {
if (irrecv.decode(&results)) {
display.clear();
display.drawString(0, 0, "IR-Code");
display.drawString(0, 16, hex2dec(getIrCode(&results)));
display.display();
setTimeSinceLastDisplaySwitch();
}
}

String hex2dec(String hex) {
unsigned long result = 0;
for (int i=0; i<hex.length(); i++) {
if (hex>=48 && hex<=57)
{
result += (hex-48)*pow(16,hex.length()-i-1);
} else if (hex>=65 && hex<=70) {
result += (hex-55)*pow(16,hex.length( )-i-1);
} else if (hex>=97 && hex<=102) {
result += (hex-87)*pow(16,hex.length()-i-1);
}
}
return uint64ToString(result);
}

String getIrCode(const decode_results *results) {
String displayText = "";
if (hasACState(results->decode_type)) {
#if DECODE_AC
for (uint16_t i = 0; results->bits > i * 8; i++) {
if (results->state < 0x10) displayText += "0";
displayText += uint64ToString(results->state, 16);
}
#endif // DECODE_AC
} else {
displayText += uint64ToString(results->value, 16);
}
return displayText;
}

void handleIr() {
for (uint8_t i = 0; i < server.args(); i++) {
if (server.argName(i) == "code") {
uint32_t code = strtoul(server.arg(i).c_str(), NULL, 10);
#if SEND_NEC
irsend.sendNEC(code, 32);
#endif // SEND_NEC
}
}
handleRoot();
}

void handleRadio() {
for (uint8_t i = 0; i < server.args(); i++) {
if (server.argName(i) == "code") {
const char* code = server.arg(i).c_str();
mySwitch_receive.disableReceive();
mySwitch_send.sendTriState(server.arg(i).c_str());
delay(50);
mySwitch_receive.enableReceive(RADIO_RECEIVER);
}
}
handleRoot();
}

void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET)?"GET":"POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++)
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
server.send(404, "text/plain", message);
}

static const char* bin2tristate(const char* bin) {
static char returnValue[50];
int pos = 0;
int pos2 = 0;
while (bin[pos]!='\0' && bin[pos+1]!='\0') {
if (bin[pos]=='0' && bin[pos+1]=='0') {
returnValue[pos2] = '0';
} else if (bin[pos]=='1' && bin[pos+1]=='1') {
returnValue[pos2] = '1';
} else if (bin[pos]=='0' && bin[pos+1]=='1') {
returnValue[pos2] = 'F';
} else {
return "not applicable";
}
pos = pos+2;
pos2++;
}
returnValue[pos2] = '\0';
return returnValue;
}

static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength) {
static char bin[64];
unsigned int i=0;

while (Dec > 0) {
bin[32+i++] = ((Dec & 1) > 0) ? '1' : '0';
Dec = Dec >> 1;
}

for (unsigned int j = 0; j< bitLength; j++) {
if (j >= bitLength - i) {
bin[j] = bin[ 31 + i - (j - (bitLength - i)) ];
} else {
bin[j] = '0';
}
}
bin[bitLength] = '\0';

return bin;
}

void checkShowIp() {
showIpButtonState = digitalRead(SHOW_IP_BUTTON);

if (showIpButtonState == HIGH) {
display.clear();
display.drawString(0, 0, "IP Address");
display.drawString(0, 16, WiFi.localIP().toString());
display.display();
setTimeSinceLastDisplaySwitch();
}
}

void checkDisplayTimeout() {
if (millis() - timeSinceLastDisplaySwitch > DISPLAY_CLEAR_TIMEOUT) {
display.clear();
display.display();
}
}

void setTimeSinceLastDisplaySwitch() {
timeSinceLastDisplaySwitch = millis();
}

void setup(void) {
// IR
irsend.begin();
digitalWrite(D6, HIGH); // as the pin works inverted after the pnp transistor set it to HIGH to switch off the ir led by default
#if DECODE_HASH
irrecv.setUnknownThreshold(MIN_UNKNOWN_SIZE);
#endif // DECODE_HASH
irrecv.enableIRIn(); // Start the receiver

// RADIO
mySwitch_send.enableTransmit(RADIO_SENDER);
mySwitch_send.setProtocol(1);
mySwitch_send.setPulseLength(187);
mySwitch_receive.enableReceive(RADIO_RECEIVER);

// DISPLAY
display.init();
display.flipScreenVertically();
display.setFont(ArialMT_Plain_16);
display.setTextAlignment(TEXT_ALIGN_LEFT);

//Serial.begin(115200);

// WIFI
wifiManager.setAPStaticIPConfig(IPAddress(192,168,0,125), IPAddress(192,168,0,1), IPAddress(255,255,255,0));
wifiManager.autoConnect("ESP-AP", "1234");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
//Serial.print(".");
}
//if (mdns.begin("esp8266", WiFi.localIP())) {
//Serial.println("MDNS responder started");
//}

// SERVER
server.on("/", handleRoot);
server.on("/ir", handleIr);
server.on("/radio", handleRadio);
server.on("/inline", [](){
server.send(200, "text/plain", "this works as well");
});
server.onNotFound(handleNotFound);
server.begin();
//Serial.println("HTTP server started");

// IP BUTTON
pinMode(SHOW_IP_BUTTON, INPUT);
}

void loop(void) {
server.handleClient();
if (mySwitch_receive.available()) {
displayRadioCode(mySwitch_receive.getReceivedValue(), mySwitch_receive.getReceivedBitlength());
mySwitch_receive.resetAvailable();
}
displayIrCode();
checkShowIp();
checkDisplayTimeout();
delay(50);
}[/src]


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.


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.
 
Zuletzt bearbeitet:

sia

gesperrt

Registriert
26 März 2015
Beiträge
5.931
Ort
FFM (NSFW)
Geil, das Projekt habe ich mir schon lange vorgenommen und jetzt macht einer meine Arbeit :)
 

War-10-ck

střelec
Veteran

Registriert
14 Juli 2013
Beiträge
5.952
Ort
Schießstand
  • Thread Starter Thread Starter
  • #3
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.
 

DandG

Such da fuq
Spaminator

Registriert
14 Juni 2016
Beiträge
2.816
Ort
In mein Haus.
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?
 

War-10-ck

střelec
Veteran

Registriert
14 Juli 2013
Beiträge
5.952
Ort
Schießstand
  • Thread Starter Thread Starter
  • #5
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.
 
Oben