Forum użytkowników automatyki budynkowej
Inne => Rasberry, Arduino, ESP8266, mikrokontrolery => Wątek zaczęty przez: Baael w Listopad 12, 2015, 10:10:22 pm
-
Zamiast drogiego na ZWave.
Przykładowy kod:
https://gist.github.com/Baael/1ba70000db7c539571cd (https://gist.github.com/Baael/1ba70000db7c539571cd)
#include <espduino.h>
#include <mqtt.h>
#include <SoftwareSerial.h>
#include <IRremote.h>
// SSID sieci wifi
#define SSID "ssid"
// Haslo sieci wifi
#define PASS "pass"
// Nalezy podac adres brokera MQTT
#define BROKER "192.168.0.1"
// nazwa pszczoly w naszym roju
char* bee_name = "hifi";
IRsend irsend;
MQTT mqtt(&esp);
SoftwareSerial espPort(11, 10); // TX, RX
ESP esp(&espPort, &Serial, 9);
// callback stanu polaczenia z siecia wifi
void wifiCb(void* response)
{
uint32_t status;
RESPONSE res(response);
if (res.getArgc() == 1) {
res.popArgs((uint8_t*)&status, 4);
if (status == STATION_GOT_IP) { mqtt.connect(BROKER, 1883); }
}
}
// callback polaczenia z brokerem MQTT
void mqttConnected(void* response)
{
// subskrybcja kanalu
mqtt.subscribe("bee/hifi/+");
// zameldowanie sie pszczoly w ulu ;) Lubie takie nazewnictwo
// mqtt.publish("swarm/bee/online", bee_name);
}
void mqttDisconnected(void* response){}
void mqttPublished(void* response){}
// callback otrzymanych danych z MQTT
void mqttData(void* response){
// przetwarzamy otrzymane informacje, na temat i payload
RESPONSE res(response);
String topic = res.popString();
String payload = res.popString();
// w zaleznosci od tematu wiadomosci
// uruchamiamy odpowiednia funkcje z payloadem jako argumentem
if (topic == "bee/hifi/volume") { setVolume(payload); }
if (topic == "bee/hifi/mode") { setMode(payload); }
if (topic == "bee/hifi/power") { triggerPower(); }
}
void setVolume(void* mode) {
if (mode == "down"){ irsend.sendSony(0xc81, 12); }
if (mode == "up") { irsend.sendSony(0x481, 12); }
}
void setMode(void* mode) {
if (data == "radio") { irsend.sendSony(0x181, 12); }
if (data == "dvd") { irsend.sendSony(0xbe1, 12); }
if (data == "aux") { irsend.sendSony(0x761, 12); }
}
// przycisk power moze tylko przelaczac aktualny stan urzadzenia
// trzeba jakos domyslic sie czy jest wlaczone czy wylaczone
void triggerPower() {
irsend.sendSony(0xa81, 12);
}
// inicjalizujemy modul esp8266
void setupESP8266() {
esp.enable();
delay(200);
esp.reset();
delay(200);
// jesli zawiesi sie w tym miejscu to warto zewrzec na chwile RST modulu z GND
while(!esp.ready());
// podpinamy callback sieci wifi
esp.wifiCb.attach(&wifiCb);
// podlaczamy sie do istniejacej sieci wifi
esp.wifiConnect(SSID,PASS);
}
// inicjalizacja MQTT
void setupMQTT() {
mqtt.begin(bee_name, "admin", "Isb_C4OGD4c3", 120, 1);
mqtt.connectedCb.attach(&mqttConnected);
mqtt.disconnectedCb.attach(&mqttDisconnected);
mqtt.publishedCb.attach(&mqttPublished);
mqtt.dataCb.attach(&mqttData);
}
void setup() {
espPort.begin(19200);
setupESP8266();
setupMQTT();
}
void loop() {
esp.process();
}
Przydatne linki do przechwytywania sygnałów IR
http://www.makeuseof.com/tag/introducing-the-tv-devil-an-easy-remote-control-arduino-prank/
https://www.pjrc.com/teensy/td_libs_IRremote.html
Schemat:
(http://content.screencast.com/users/baael/folders/Jing/media/d4b546bc-fd42-4dec-afd3-02a1d7bbfba3/2015-11-12_2131.png)
Efekt :)
(http://content.screencast.com/users/baael/folders/Jing/media/4c182a34-f786-48fb-a20f-c3d958a835b6/2015-11-12_2146.png)
Potrzebne:
1. http://z3t0.github.io/Arduino-IRremote/
2. https://github.com/tuanpmt/espduino
-
fajne, dzieki za opis :-)
-
Wczoraj wieczorem "popełniłem" podobny moduł.
Funkcje modułu:
- odbieranie sygnału IR z pilotów i publikowanie do brokera MQTT
- odbieranie komunikatu z brokera i transmisja podczerwienią z odpowiednim kodowanie
- wysłanie kodów do dekodera Nki w celu przełączenia wyjścia video HDMI i EURO - to był zapalnik do opracowania tego modułu.
Odbiornik IR podłączony jest do GPIO2 a dioda nadawcza przez tranzystor do GPIO0. Uwaga - trzeba dodać rezystor podciągający do GPIO0, inaczej ESP po restarcie będzie wchodził w tryb programowania.
Format komunikatów
kierunek IR -> MQTT
TOPIC: esp8266/02/receiver/RC5/12/ADDR
------------------- ^ ^ ^
prefix ----/ | | |
kodowanie ----------------/ | |
ilosc bitów -----------------/ |
Adres (dotyczy PANASONIC) --------/
MESSAGE: kod zapisany dziesiętnie
kierunek MQTT -> IR
TOPIC: esp8266/02/sender/KOD/BITS/ADDR
----------------- ^ ^ ^
prefix ----/ | | |
kodowanie --------------/ | |
ilosc bitów ---------------/ |
Adres (dotyczy PANASONIC) -------/
MESSAGE: kod zapisany dziesiętnie
Komunikaty dekodera Nki
TOPIC: esp8266/02/sender/NC/HDMI <- włączenie HDMI
TOPIC: esp8266/02/sender/NC/EURO <- włączenie EURO
Przykładowe użycie w Openhabie
items
Switch ir_philips_on "Philips Power" (gIR) {mqtt=">[mosquitto:esp8266/02/sender/RC5/12:command:ON:56]"}
Switch ir_nc_hdmi "NC+ HDMI" <ir> (gIR) {mqtt=">[mosquitto:esp8266/02/sender/NC/HDMI:command:ON:1]"}
rules
// Zauważyłem, że do Philipsa trzeba komendy wysyłać podwójnie
rule sendPhilipsOn
when
Item ir_philips_on changed from OFF to ON
then
Thread::sleep(500)
sendCommand(ir_philips_on,ON)
postUpdate(ir_philips_on,OFF)
end
// Warto "podnieść" klawisz po jego użyciu
rule buttonAutoRelease
when
Item ir_nc_hdmi changed from OFF to ON
or
Item ir_nc_euro changed from OFF to ON
then
Thread::sleep(500)
postUpdate(ir_nc_hdmi,OFF)
postUpdate(ir_nc_euro,OFF)
end
ToDo:
- obsługa kodów nieznanych i możliwość transmisji danych RAW
- obsługa kodów innych niż RC5 i NEC (akurat tych potrzebowałem)
/*
* MQTT IR server
* An IR LED must be connected to ESP8266 pin 0
* An IR receiver to pin 2
* used library:
* https://github.com/markszabo/IRremoteESP8266
* Version 0.1 January, 2016
*/
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <IRremoteESP8266.h>
#include <PubSubClient.h>
// PIN definition
#define RECV_PIN 2
#define SEND_PIN 0
const char* ssid = "....";
const char* password = "....";
const char* topicRaport = "esp8266/02/info";
const char* topicSubscribe = "esp8266/02/sender/#";
const char* topicPrefix = "esp8266/02/receiver";
const char* mqtt_server = "....";
const char* mqtt_user = "...";
const char* mqtt_pass = "...";
String clientName; // MQTT client name
char message_buff[100];
IRrecv irrecv(RECV_PIN);
IRsend irsend(SEND_PIN);
WiFiClient wifiClient;
void callback(char* topic, byte* payload, unsigned int length);
void connect_to_MQTT();
PubSubClient client(mqtt_server, 1883, callback, wifiClient);
// -----------------------------------------------------------------
// MQTT receiver
void callback(char* topic, byte* payload, unsigned int length) {
int i = 0;
Serial.println("Message arrived: topic: " + String(topic));
Serial.println("Length: " + String(length,DEC));
// create character buffer with ending null terminator (string)
for(i=0; i<length; i++) {
message_buff[i] = payload[i];
}
message_buff[i] = '\0';
unsigned int freq=38;
String msgString = String(message_buff);
String msgTopic = String(topic);
unsigned long msgInt = msgString.toInt();
unsigned int rawData_s1[35] = {250,950, 200,2000, 200,1200, 200,2850, 200,1350, 200,1350, 200,1050, 200,2150, 200,12950, 200,950, 200,1200, 200,800, 200,1200, 200,1600, 200,1200, 200,800, 200,800, 200}; // UNKNOWN C0092718
unsigned int rawData_s2[37] = {100,5850, 200,950, 200,2000, 200,1200, 200,2850, 200,1350, 200,1350, 200,1050, 200,2150, 200,12950, 200,950, 200,2300, 200,1900, 200,1200, 200,1650, 200,1200, 200,800, 200,800, 200}; // UNKNOWN 4AE2F613
unsigned int rawData_11[35] = {250,950, 200,2000, 200,1250, 200,2850, 200,1350, 200,1350, 200,1050, 200,2150, 200,12950, 200,950, 200,800, 200,800, 200,1200, 200,800, 200,2450, 200,800, 200,800, 200}; // UNKNOWN 290BC97A
unsigned int rawData_12[35] = {250,950, 200,2000, 200,1200, 200,2850, 200,1350, 200,1350, 200,1050, 200,2150, 200,12950, 200,950, 200,1900, 200,1900, 200,1200, 200,800, 200,2450, 200,800, 200,800, 200}; // UNKNOWN 8FEB0411
unsigned int rawData_91[35] = {250,950, 200,2000, 200,1200, 200,2850, 200,1350, 200,1350, 200,1100, 200,2150, 200,12950, 200,950, 200,1750, 200,800, 200,1200, 200,1200, 200,1100, 200,800, 200,800, 200}; // UNKNOWN 19B50A9
unsigned int rawData_92[35] = {250,950, 200,2000, 200,1250, 200,2850, 200,1350, 200,1350, 200,1100, 200,2150, 200,12950, 200,950, 200,2850, 200,1900, 200,1200, 200,1200, 200,1100, 200,800, 200,800, 200}; // UNKNOWN 442CD28F
Serial.println("Payload String: " + msgString);
if (msgTopic=="esp8266/02/sender/NC/HDMI") // *9
{
irsend.sendRaw(rawData_s1, 35, freq);
irsend.sendRaw(rawData_s2, 37, freq);
irsend.sendRaw(rawData_91, 35, freq);
irsend.sendRaw(rawData_92, 35, freq);
Serial.println("Send NC+ HDMI: *9");
}
else if (msgTopic=="esp8266/02/sender/NC/EURO") // *1
{
irsend.sendRaw(rawData_s1, 35, freq);
irsend.sendRaw(rawData_s2, 37, freq);
irsend.sendRaw(rawData_11, 35, freq);
irsend.sendRaw(rawData_12, 35, freq);
Serial.println("Send NC+ EURO: *1");
} else {
// struktura "esp8266/02/sender/typ[/bits[/panasonic_address]]"
int endOfBits;
String irTypStr = "";
String irBitsStr = "";
int irBitsInt=-1;
String irPanasAddrStr = "";
int endOfTyp = msgTopic.indexOf("/",20);
if (endOfTyp == -1)
{
// One element - only irTyp
irTypStr = msgTopic.substring(18);
} else {
// irTyp exists i cos dalej
irTypStr = msgTopic.substring(18, endOfTyp);
endOfBits = msgTopic.indexOf("/",endOfTyp+1);
if (endOfBits== -1)
{
// irBits jest na koncy
irBitsStr = msgTopic.substring(endOfTyp+1);
} else {
// irBits i cos dalej
irBitsStr = msgTopic.substring(endOfTyp+1, endOfBits);
irPanasAddrStr = msgTopic.substring(endOfBits+1);
}
irBitsInt = irBitsStr.toInt();
}
Serial.println(irTypStr);
Serial.println(irBitsStr);
Serial.println(irPanasAddrStr);
if (irTypStr=="NEC") {
Serial.print("Send NEC:");
Serial.println(msgInt);
irsend.sendNEC(msgInt, 36);
} else if (irTypStr=="RC5") {
Serial.print("Send RC5:");
Serial.print(msgInt);
Serial.print(" (");
Serial.print(irBitsInt);
Serial.println("-bits)");
irsend.sendRC5(msgInt, irBitsInt);
}
/*
TODO:
case "UNKNOWN":
case "SONY":
case "RC6":
case "DISH":
case "SHARP":
case "JVC":
case "SANYO":
case "MITSUBISHI":
case "SAMSUNG":
case "LG":
case "WHYNTER":
case "AIWA_RC_T501":
case "PANASONIC":
*/
}
}
// -----------------------------------------------------------------
String macToStr(const uint8_t* mac)
{
String result;
for (int i = 0; i < 6; ++i) {
result += String(mac[i], 16);
if (i < 5)
result += ':';
}
return result;
}
// -----------------------------------------------------------------
void setup(void){
irsend.begin(); // Start IR sender
irrecv.enableIRIn(); // Start the receiver
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
clientName += "esp8266-";
uint8_t mac[6];
WiFi.macAddress(mac);
clientName += macToStr(mac);
clientName += "-";
clientName += String(micros() & 0xff, 16);
connect_to_MQTT();
}
// -----------------------------------------------------------------
void connect_to_MQTT() {
Serial.print("Connecting to ");
Serial.print(mqtt_server);
Serial.print(" as ");
Serial.println(clientName);
int is_conn = 0;
while (is_conn == 0) {
if (client.connect((char*) clientName.c_str(), mqtt_user, mqtt_pass)) {
Serial.println("Connected to MQTT broker");
client.publish(topicRaport, (char*) clientName.c_str());
IPAddress myIp = WiFi.localIP();
char myIpString[24];
sprintf(myIpString, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]);
client.publish(topicRaport, (char*) myIpString);
Serial.print("Topic is: ");
Serial.println(topicSubscribe);
if (client.subscribe(topicSubscribe)){
Serial.println("Successfully subscribed");
}
is_conn = 1;
}
else {
Serial.print("MQTT connect failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
// -----------------------------------------------------------------
// Encodig of data
void encoding (decode_results *results, char * result_encoding)
{
switch (results->decode_type) {
default:
case UNKNOWN: strncpy(result_encoding,"UNKNOWN\0",8); break ;
case NEC: strncpy(result_encoding,"NEC\0",4); break ;
case SONY: strncpy(result_encoding,"SONY\0",5); break ;
case RC5: strncpy(result_encoding,"RC5\0",4); break ;
case RC6: strncpy(result_encoding,"RC6\0",4); break ;
case DISH: strncpy(result_encoding,"DISH\0",5); break ;
case SHARP: strncpy(result_encoding,"SHARP\0",6); break ;
case JVC: strncpy(result_encoding,"JVC\0",4); break ;
case SANYO: strncpy(result_encoding,"SANYO\0",6); break ;
case MITSUBISHI: strncpy(result_encoding,"MITSUBISHI\0",11); break ;
case SAMSUNG: strncpy(result_encoding,"SAMSUNG\0",8); break ;
case LG: strncpy(result_encoding,"LG\0",3); break ;
case WHYNTER: strncpy(result_encoding,"WHYNTER\0",8); break ;
case AIWA_RC_T501: strncpy(result_encoding,"AIWA_RC_T501\0",13); break ;
case PANASONIC: strncpy(result_encoding,"PANASONIC\0",11); break ;
}
}
// -----------------------------------------------------------------
void loop(void){
client.loop();
if (! client.connected()) {
Serial.println("Not connected to MQTT....");
connect_to_MQTT();
}
decode_results results; // Somewhere to store the results
if (irrecv.decode(&results)) { // Grab an IR code
char myTopic[100];
char myTmp[50];
char myValue[500];
encoding (&results, myTmp);
if (results.decode_type == PANASONIC) { //Panasonic has address
// struktura "prefix/typ/bits[/panasonic_address]"
sprintf(myTopic, "%s/%s/%d/%d", topicPrefix, myTmp, results.bits, results.panasonicAddress );
} else {
sprintf(myTopic, "%s/%s/%d", topicPrefix, myTmp, results.bits );
}
if (results.decode_type != UNKNOWN) {
sprintf(myValue, "%d", results.value);
client.publish((char*) myTopic, (char*) myValue );
}
irrecv.resume(); // Prepare for the next value
}
}
-
Aktualna wersja IR transceiver-a jest na githubie:
https://github.com/enc-X/mqtt-ir-transceiver
- Obsługuje tryby RAW - można programowować przez MQTT swoje kody a następnie wysyłać je przez IR
- Wprowadziłem tryb konfiguracji WiFi i MQTT