/* xdrv_17_rcswitch.ino - RF transceiver using RcSwitch library for Sonoff-Tasmota Copyright (C) 2019 Theo Arends This program 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. This program 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 USE_RC_SWITCH /*********************************************************************************************\ * RF send and receive using RCSwitch library https://github.com/sui77/rc-switch/ \*********************************************************************************************/ #define XDRV_17 17 #define D_JSON_RF_PROTOCOL "Protocol" #define D_JSON_RF_BITS "Bits" #define D_JSON_RF_DATA "Data" #define D_CMND_RFSEND "RFSend" #define D_JSON_RF_PULSE "Pulse" #define D_JSON_RF_REPEAT "Repeat" const char kRfSendCommands[] PROGMEM = "|" // No prefix D_CMND_RFSEND; void (* const RfSendCommand[])(void) PROGMEM = { &CmndRfSend }; #include RCSwitch mySwitch = RCSwitch(); #define RF_TIME_AVOID_DUPLICATE 1000 // Milliseconds uint32_t rf_lasttime = 0; void RfReceiveCheck(void) { if (mySwitch.available()) { unsigned long data = mySwitch.getReceivedValue(); unsigned int bits = mySwitch.getReceivedBitlength(); int protocol = mySwitch.getReceivedProtocol(); int delay = mySwitch.getReceivedDelay(); AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RFR: Data 0x%lX (%u), Bits %d, Protocol %d, Delay %d"), data, data, bits, protocol, delay); uint32_t now = millis(); if ((now - rf_lasttime > RF_TIME_AVOID_DUPLICATE) && (data > 0)) { rf_lasttime = now; char stemp[16]; if (Settings.flag.rf_receive_decimal) { // SetOption28 (0 = hexadecimal, 1 = decimal) snprintf_P(stemp, sizeof(stemp), PSTR("%u"), (uint32_t)data); } else { snprintf_P(stemp, sizeof(stemp), PSTR("\"0x%lX\""), (uint32_t)data); } ResponseTime_P(PSTR(",\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_RF_DATA "\":%s,\"" D_JSON_RF_BITS "\":%d,\"" D_JSON_RF_PROTOCOL "\":%d,\"" D_JSON_RF_PULSE "\":%d}}"), stemp, bits, protocol, delay); MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_RFRECEIVED)); XdrvRulesProcess(); #ifdef USE_DOMOTICZ DomoticzSensor(DZ_COUNT, data); // Send data as Domoticz Counter value #endif // USE_DOMOTICZ } mySwitch.resetAvailable(); } } void RfInit(void) { if (pin[GPIO_RFSEND] < 99) { mySwitch.enableTransmit(pin[GPIO_RFSEND]); } if (pin[GPIO_RFRECV] < 99) { mySwitch.enableReceive(pin[GPIO_RFRECV]); } } /*********************************************************************************************\ * Commands \*********************************************************************************************/ void CmndRfSend(void) { bool error = false; if (XdrvMailbox.data_len) { unsigned long data = 0; unsigned int bits = 24; int protocol = 1; int repeat = 10; int pulse = 350; char dataBufUc[XdrvMailbox.data_len]; UpperCase(dataBufUc, XdrvMailbox.data); StaticJsonBuffer<150> jsonBuf; // ArduinoJSON entry used to calculate jsonBuf: JSON_OBJECT_SIZE(5) + 40 = 134 JsonObject &root = jsonBuf.parseObject(dataBufUc); if (root.success()) { // RFsend {"data":0x501014,"bits":24,"protocol":1,"repeat":10,"pulse":350} char parm_uc[10]; data = strtoul(root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_DATA))], nullptr, 0); // Allow decimal (5246996) and hexadecimal (0x501014) input bits = root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_BITS))]; protocol = root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_PROTOCOL))]; repeat = root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_REPEAT))]; pulse = root[UpperCase_P(parm_uc, PSTR(D_JSON_RF_PULSE))]; } else { // RFsend data, bits, protocol, repeat, pulse char *p; uint8_t i = 0; for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 5; str = strtok_r(nullptr, ", ", &p)) { switch (i++) { case 0: data = strtoul(str, nullptr, 0); // Allow decimal (5246996) and hexadecimal (0x501014) input break; case 1: bits = atoi(str); break; case 2: protocol = atoi(str); break; case 3: repeat = atoi(str); break; case 4: pulse = atoi(str); } } } if (!protocol) { protocol = 1; } mySwitch.setProtocol(protocol); if (!pulse) { pulse = 350; } // Default pulse length for protocol 1 mySwitch.setPulseLength(pulse); if (!repeat) { repeat = 10; } // Default at init mySwitch.setRepeatTransmit(repeat); if (!bits) { bits = 24; } // Default 24 bits if (data) { mySwitch.send(data, bits); ResponseCmndDone(); } else { error = true; } } else { error = true; } if (error) { Response_P(PSTR("{\"" D_CMND_RFSEND "\":\"" D_JSON_NO " " D_JSON_RF_DATA ", " D_JSON_RF_BITS ", " D_JSON_RF_PROTOCOL ", " D_JSON_RF_REPEAT " " D_JSON_OR " " D_JSON_RF_PULSE "\"}")); } } /*********************************************************************************************\ * Interface \*********************************************************************************************/ bool Xdrv17(uint8_t function) { bool result = false; if ((pin[GPIO_RFSEND] < 99) || (pin[GPIO_RFRECV] < 99)) { switch (function) { case FUNC_EVERY_50_MSECOND: if (pin[GPIO_RFRECV] < 99) { RfReceiveCheck(); } break; case FUNC_COMMAND: if (pin[GPIO_RFSEND] < 99) { result = DecodeCommand(kRfSendCommands, RfSendCommand); } break; case FUNC_INIT: RfInit(); break; } } return result; } #endif // USE_RC_SWITCH