From af5e4e8ec9b2645f1e6e9dd4e43f21ca7911e39b Mon Sep 17 00:00:00 2001 From: Florian <1technophile@users.noreply.github.com> Date: Fri, 24 Nov 2017 23:00:21 +0100 Subject: [PATCH] Zgateway srfb (#143) * compatibility with sonoff rf bridge #81 * update extract_char call --- OpenMQTTGateway.ino | 58 ++++++++--- User_config.h | 10 +- ZgatewayBT.ino | 21 +--- ZgatewaySRFB.ino | 236 ++++++++++++++++++++++++++++++++++++++++++++ config_SRFB.h | 62 ++++++++++++ tests/Test_config.h | 2 + 6 files changed, 356 insertions(+), 33 deletions(-) create mode 100644 ZgatewaySRFB.ino create mode 100644 config_SRFB.h diff --git a/OpenMQTTGateway.ino b/OpenMQTTGateway.ino index 1210dc4c..f5b8a4e6 100644 --- a/OpenMQTTGateway.ino +++ b/OpenMQTTGateway.ino @@ -135,7 +135,12 @@ void setup() { #ifdef ESP8266 //Launch serial for debugging purposes - Serial.begin(SERIAL_BAUD, SERIAL_8N1, SERIAL_TX_ONLY); + #ifdef ZgatewaySRFB + Serial.begin(SERIAL_BAUD); // in the case of sonoff RF Bridge the link to the RF emitter/receiver is made by serial and need TX/RX + #else + Serial.begin(SERIAL_BAUD, SERIAL_8N1, SERIAL_TX_ONLY); + #endif + //Begining wifi connection in case of ESP8266 setup_wifi(); // Port defaults to 8266 @@ -282,29 +287,28 @@ void loop() #endif // Receive loop, if data received by RF433 or IR send it by MQTT #ifdef ZgatewayRF - boolean resultRF = RFtoMQTT(); - if(resultRF) + if(RFtoMQTT()) trc(F("RFtoMQTT OK")); #endif #ifdef ZgatewayRF2 - boolean resultRF2 = RF2toMQTT(); - if(resultRF2) + if(RF2toMQTT()) trc(F("RF2toMQTT OK")); #endif + #ifdef ZgatewaySRFB + if(SRFBtoMQTT()) + trc(F("SRFBtoMQTT OK")); + #endif #ifdef ZgatewayIR - boolean resultIR = IRtoMQTT(); - if(resultIR) + if(IRtoMQTT()) trc(F("IRtoMQTT OK")); delay(100); #endif #ifdef ZgatewayBT - boolean resultBT = BTtoMQTT(); - if(resultBT) + if(BTtoMQTT()) trc(F("BTtoMQTT OK")); #endif #ifdef ZgatewayRFM69 - boolean resultRFM69 = RFM69toMQTT(); - if(resultRFM69) + if(RFM69toMQTT()) trc(F("RFM69toMQTT OK")); #endif } @@ -373,6 +377,9 @@ void receivingMQTT(char * topicOri, char * datacallback) { #ifdef ZgatewayRF2 MQTTtoRF2(topicOri, datacallback); #endif +#ifdef ZgatewaySRFB + MQTTtoSRFB(topicOri, datacallback); +#endif #ifdef ZgatewayIR MQTTtoIR(topicOri, datacallback); #endif @@ -381,6 +388,35 @@ void receivingMQTT(char * topicOri, char * datacallback) { #endif } +void extract_char(char * token_char, char * subset, int start ,int l, boolean reverse, boolean isNumber){ + char tmp_subset[l+1]; + memcpy( tmp_subset, &token_char[start], l ); + tmp_subset[l] = '\0'; + if (isNumber){ + char tmp_subset2[l+1]; + if (reverse) revert_hex_data(tmp_subset, tmp_subset2, l+1); + else strncpy( tmp_subset2, tmp_subset , l+1); + long long_value = strtoul(tmp_subset2, NULL, 16); + sprintf(tmp_subset2, "%d", long_value); + strncpy( subset, tmp_subset2 , l+1); + }else{ + if (reverse) revert_hex_data(tmp_subset, subset, l+1); + else strncpy( subset, tmp_subset , l+1); + } +} + +void revert_hex_data(char * in, char * out, int l){ + //reverting array 2 by 2 to get the data in good order + int i = l-2 , j = 0; + while ( i != -2 ) { + if (i%2 == 0) out[j] = in[i+1]; + else out[j] = in[i-1]; + j++; + i--; + } + out[l-1] = '\0'; +} + //trace void trc(String msg){ if (TRACE) { diff --git a/User_config.h b/User_config.h index 310f0e17..76bcdf37 100644 --- a/User_config.h +++ b/User_config.h @@ -29,8 +29,6 @@ along with this program. If not, see . */ -/*----------------------------USER PARAMETERS-----------------------------*/ -#define SERIAL_BAUD 115200 /*-------------DEFINE YOUR NETWORK PARAMETERS BELOW----------------*/ //MQTT Parameters definition #define mqtt_server "192.168.1.17" @@ -70,6 +68,8 @@ const byte subnet[] = { 255, 255, 255, 0 }; //ip adress #define ZgatewayRF #include "config_RF.h" //#define ZgatewayRF2 + //#define ZgatewaySRFB + //#include "config_SRFB.h" #define ZgatewayIR #include "config_IR.h" #define ZgatewayBT @@ -117,6 +117,12 @@ const byte subnet[] = { 255, 255, 255, 0 }; //ip adress #endif /*----------------------------OTHER PARAMETERS-----------------------------*/ /*-------------------CHANGING THEM IS NOT COMPULSORY-----------------------*/ +/*----------------------------USER PARAMETERS-----------------------------*/ +#ifdef ZgatewaySRFB + #define SERIAL_BAUD 19200 +#else + #define SERIAL_BAUD 115200 +#endif /*--------------MQTT general topics-----------------*/ // global MQTT subject listened by the gateway to execute commands (send RF, IR or others) #define subjectMQTTtoX "home/commands/#" diff --git a/ZgatewayBT.ino b/ZgatewayBT.ino index 57d2da9f..b224c732 100644 --- a/ZgatewayBT.ino +++ b/ZgatewayBT.ino @@ -83,7 +83,7 @@ boolean BTtoMQTT() { for(int i =0; i<6;i++) { - extract_char(token_char,d[i].extract,d[i].start, d[i].len ,d[i].reverse); + extract_char(token_char,d[i].extract,d[i].start, d[i].len ,d[i].reverse, false); if (i == 3) d[5].len = (int)strtol(d[i].extract, NULL, 16) * 2; // extracting the length of the rest data } @@ -162,25 +162,6 @@ boolean process_miflora_data(char * rest_data, char * mac_adress){ return true; } -void revert_hex_data(char * in, char * out, int l){ - //reverting array 2 by 2 to get the data in good order - int i = l-2 , j = 0; - while ( i != -2 ) { - if (i%2 == 0) out[j] = in[i+1]; - else out[j] = in[i-1]; - j++; - i--; - } - out[l-1] = '\0'; -} - -void extract_char(char * token_char, char * subset, int start ,int l, boolean reverse){ - char tmp_subset[l+1]; - memcpy( tmp_subset, &token_char[start], l ); - tmp_subset[l] = '\0'; - if (reverse) revert_hex_data(tmp_subset, subset, l+1); - else strncpy( subset, tmp_subset , l+1); -} #endif #ifdef ZgatewayBT_stable diff --git a/ZgatewaySRFB.ino b/ZgatewaySRFB.ino new file mode 100644 index 00000000..f8e8ff87 --- /dev/null +++ b/ZgatewaySRFB.ino @@ -0,0 +1,236 @@ +/* + OpenMQTTGateway - ESP8266 or Arduino program for home automation + + Act as a wifi or ethernet gateway between your 433mhz/infrared IR signal and a MQTT broker + Send and receiving command by MQTT + + This gateway enables to: + - receive MQTT data from a topic and send RF 433Mhz signal corresponding to the received MQTT data using SONOFF RF BRIDGE + - publish MQTT data to a different topic related to received 433Mhz signal using SONOFF RF BRIDGE + + This implementation into OpenMQTTGateway is based on Xose Pérez work ESPURNA (https://bitbucket.org/xoseperez/espurna) + + Copyright (C) 2016-2017 by Xose Pérez + OpenMQTTGateway integration by Florian ROBERT + + This file is part of OpenMQTTGateway. + + OpenMQTTGateway is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenMQTTGateway is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef ZgatewaySRFB + +unsigned char _uartbuf[RF_MESSAGE_SIZE+3] = {0}; +unsigned char _uartpos = 0; + +void MQTTtoSRFB(char * topicOri, char * datacallback) { + + // RF DATA ANALYSIS + String topic = topicOri; + + if (topic == subjectMQTTtoSRFB){ + + int valueRPT = 0; + int valueMiniPLSL = 0; + int valueMaxiPLSL = 0; + int valueSYNC = 0; + + int pos = topic.lastIndexOf(SRFBRptKey); + if (pos != -1){ + pos = pos + +strlen(SRFBRptKey); + valueRPT = (topic.substring(pos,pos + 1)).toInt(); + trc(F("SRFB Repeat:")); + trc(String(valueRPT)); + } + + int pos2 = topic.lastIndexOf(SRFBminipulselengthKey); + if (pos2 != -1) { + pos2 = pos2 + strlen(SRFBminipulselengthKey); + valueMiniPLSL = (topic.substring(pos2,pos2 + 3)).toInt(); + trc(F("RF Mini Pulse Lgth:")); + trc(String(valueMiniPLSL)); + } + + int pos3 = topic.lastIndexOf(SRFBmaxipulselengthKey); + if (pos3 != -1){ + pos3 = pos3 + strlen(SRFBmaxipulselengthKey); + valueMaxiPLSL = (topic.substring(pos3,pos3 + 2)).toInt(); + trc(F("RF Maxi Pulse Lgth:")); + trc(String(valueMaxiPLSL)); + } + + int pos4 = topic.lastIndexOf(SRFBsyncKey); + if (pos4 != -1){ + pos4 = pos4 + strlen(SRFBsyncKey); + valueSYNC = (topic.substring(pos4,pos4 + 2)).toInt(); + trc(F("RF sync:")); + trc(String(valueSYNC)); + } + + trc(F("MQTTtoSRFB default prts")); + if (valueRPT == 0) valueRPT = 1; + if (valueMiniPLSL == 0) valueMiniPLSL = 320; + if (valueMaxiPLSL == 0) valueMaxiPLSL = 900; + if (valueSYNC == 0) valueSYNC = 9500; + + byte hex_valueMiniPLSL[2]; + hex_valueMiniPLSL[0] = (int)((valueMiniPLSL >> 8) & 0xFF) ; + hex_valueMiniPLSL[1] = (int)(valueMiniPLSL & 0xFF) ; + + byte hex_valueMaxiPLSL[2]; + hex_valueMaxiPLSL[0] = (int)((valueMaxiPLSL >> 8) & 0xFF) ; + hex_valueMaxiPLSL[1] = (int)(valueMaxiPLSL & 0xFF) ; + + byte hex_valueSYNC[2]; + hex_valueSYNC[0] = (int)((valueSYNC >> 8) & 0xFF) ; + hex_valueSYNC[1] = (int)(valueSYNC & 0xFF) ; + + unsigned long data = strtoul(datacallback, NULL, 10); // we will not be able to pass values > 4294967295 + byte hex_data[3]; + hex_data[0] = (unsigned long)((data >> 16) & 0xFF) ; + hex_data[1] = (unsigned long)((data >> 8) & 0xFF) ; + hex_data[2] = (unsigned long)(data & 0xFF) ; + + byte message_b[RF_MESSAGE_SIZE]; + + memcpy(message_b, hex_valueSYNC, 2); + memcpy(message_b + 2, hex_valueMiniPLSL, 2); + memcpy(message_b + 4, hex_valueMaxiPLSL, 2); + memcpy(message_b + 6, hex_data, 3); + + _rfbSend(message_b, valueRPT); + // Acknowledgement to the GTWRF topic + boolean result = client.publish(subjectGTWSRFBtoMQTT, datacallback);// we acknowledge the sending by publishing the value to an acknowledgement topic, for the moment even if it is a signal repetition we acknowledge also + if (result) trc(F("MQTTtoSRFB ack pub.")); + } +} + +void _rfbSend(byte * message) { + Serial.println(); + Serial.write(RF_CODE_START); + Serial.write(RF_CODE_RFOUT); + for (unsigned char j=0; j0) { + unsigned long start = millis(); + while (millis() - start < RF_SEND_DELAY) delay(1); + } + _rfbSend(message); + } +} + +boolean SRFBtoMQTT() { + + static bool receiving = false; + + while (Serial.available()) { + yield(); + byte c = Serial.read(); + + if (receiving) { + if (c == RF_CODE_STOP) { + _rfbDecode(); + receiving = false; + } else { + _uartbuf[_uartpos++] = c; + } + } else if (c == RF_CODE_START) { + _uartpos = 0; + receiving = true; + } + + } + return receiving; +} + +void _rfbDecode() { + + static unsigned long last = 0; + if (millis() - last < RF_RECEIVE_DELAY) return; + last = millis(); + + byte action = _uartbuf[0]; + char buffer[RF_MESSAGE_SIZE * 2 + 1] = {0}; + + if (action == RF_CODE_RFIN) { + _rfbToChar(&_uartbuf[1], buffer); + client.publish(subjectSRFBtoMQTTRaw,buffer); + + char val[7]= {0}; + extract_char(buffer, val, 12 ,7, false,true); + client.publish(subjectSRFBtoMQTT,val); + + char val_Tsyn[4]= {0}; + extract_char(buffer, val_Tsyn, 0 ,4, false, true); + client.publish(subjectSRFBtoMQTTTsyn,val_Tsyn); + + char val_Thigh[4]= {0}; + extract_char(buffer, val_Thigh, 4 ,4, false, true); + client.publish(subjectSRFBtoMQTTThigh,val_Thigh); + + char val_Tlow[4]= {0}; + extract_char(buffer, val_Tlow, 8 ,4, false, true); + client.publish(subjectSRFBtoMQTTTlow,val_Tlow); + + _rfbAck(); + } +} + +void _rfbAck() { + trc("[RFBRIDGE] Sending ACK\n"); + Serial.println(); + Serial.write(RF_CODE_START); + Serial.write(RF_CODE_ACK); + Serial.write(RF_CODE_STOP); + Serial.flush(); + Serial.println(); +} + +/* +From an hexa char array ("A220EE...") to a byte array (half the size) + */ +bool _rfbToArray(const char * in, byte * out) { + if (strlen(in) != RF_MESSAGE_SIZE * 2) return false; + char tmp[3] = {0}; + for (unsigned char p = 0; p + + This file is part of OpenMQTTGateway. + + OpenMQTTGateway is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenMQTTGateway is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/*-------------------RF topics & parameters----------------------*/ +//433Mhz MQTT Subjects and keys +#define subjectMQTTtoSRFB "home/commands/MQTTtoSRFB" +#define subjectMQTTtoSRFBRaw "home/commands/MQTTtoSRFB/Raw" +#define subjectSRFBtoMQTTTsyn "home/SRFBtoMQTT/Tsyn" +#define subjectSRFBtoMQTTTlow "home/SRFBtoMQTT/Tlow" +#define subjectSRFBtoMQTTThigh "home/SRFBtoMQTT/Thigh" +#define subjectSRFBtoMQTT "home/SRFBtoMQTT" +#define subjectGTWSRFBtoMQTT "home/SRFBtoMQTT" +#define subjectSRFBtoMQTTRaw "home/SRFBtoMQTT/Raw" +#define SRFBRptKey "RPT_" +#define SRFBmaxipulselengthKey "Thigh_" +#define SRFBminipulselengthKey "Tlow_" +#define SRFBsyncKey "Tsyn_" +// ----------------------------------------------------------------------------- +// RFBRIDGE +// ----------------------------------------------------------------------------- + +#define RF_SEND_TIMES 4 // How many times to send the message +#define RF_SEND_DELAY 500 // Interval between sendings in ms +#define RF_RECEIVE_DELAY 500 // Interval between recieving in ms (avoid debouncing) + +// ----------------------------------------------------------------------------- +// DEFINITIONS +// ----------------------------------------------------------------------------- + +#define RF_MESSAGE_SIZE 9 +#define RF_CODE_START 0xAA +#define RF_CODE_ACK 0xA0 +#define RF_CODE_RFIN 0xA4 +#define RF_CODE_RFOUT 0xA5 +#define RF_CODE_STOP 0x55 + + + diff --git a/tests/Test_config.h b/tests/Test_config.h index 81208f71..ac1337b1 100644 --- a/tests/Test_config.h +++ b/tests/Test_config.h @@ -69,6 +69,8 @@ const byte subnet[] = { 255, 255, 255, 0 }; //ip adress #ifdef ESP8266 // for nodemcu, weemos and esp8266 #define ZgatewayRF #include "config_RF.h" + #define ZgatewaySRFB + #include "config_SRFB.h" #define ZgatewayRF2 #define ZgatewayIR #include "config_IR.h"