diff --git a/CHANGELOG.md b/CHANGELOG.md index f89ec5b9d..19a62b2a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file. - Fallback NTP server from x.pool.ntp.org if no ntpservers are configured - TyuaMcu update 2/3 by Federico Leoni (#10004) - Optional CCloader support for CC25xx Zigbee or CC26xx BLE by Christian Baars (#9970) +- Command ``RfProtocol`` to control RcSwitch receive protocols by BBBits (#10063) ### Breaking Changed - KNX DPT9 (16-bit float) to DPT14 (32-bit float) by Adrian Scillato (#9811, #9888) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e07024aeb..b09b2189b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -60,6 +60,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota ### Added - Command ``SetOption115 1`` to enable ESP32 MiBle - Command ``SetOption116 1`` to disable auto-query of zigbee light devices (avoids network storms with large groups) +- Command ``RfProtocol`` to control RcSwitch receive protocols by BBBits (#10063) - Commands ``TuyaRGB``, ``TuyaEnum`` and ``TuyaEnumList`` (#9769) - Zigbee command ``ZbInfo`` and prepare support for EEPROM - Zigbee command ``ZbLeave`` to unpair a device diff --git a/lib/lib_rf/rc-switch/src/RCSwitch.cpp b/lib/lib_rf/rc-switch/src/RCSwitch.cpp index 9fddf23df..d222551b3 100644 --- a/lib/lib_rf/rc-switch/src/RCSwitch.cpp +++ b/lib/lib_rf/rc-switch/src/RCSwitch.cpp @@ -1,7 +1,7 @@ /* RCSwitch - Arduino libary for remote control outlet switches Copyright (c) 2011 Suat Özgür. All right reserved. - + Contributors: - Andre Koehler / info(at)tomate-online(dot)de - Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com @@ -13,7 +13,7 @@ - Robert ter Vehn / .(at)gmail(dot)com - Johann Richard / .(at)gmail(dot)com - Vlad Gheorghe / .(at)gmail(dot)com https://github.com/vgheo - + Project home: https://github.com/sui77/rc-switch/ This library is free software; you can redistribute it and/or @@ -57,13 +57,13 @@ /* Protocol description format * * {Pulse length, Preamble, Sync bit, "0" bit, "1" bit, Inverted Signal, Guard time} - * + * * Pulse length: pulse duration Te in microseconds, * example 350 * Preamble: Alternating high and low levels * {20, 1} means 20 alternations of 1 Te duration * _ _ _ _ _ _ _ _ _ _ - * | |_| |_| |_| |_| |_| |_| |_| |_| |_| |_ + * | |_| |_| |_| |_| |_| |_| |_| |_| |_| |_ * Sync bit: Header and clock * {1, 31} means 1 pulse long Te high and 31 low * _ @@ -133,8 +133,8 @@ enum { }; #if not defined( RCSwitchDisableReceiving ) - volatile unsigned long long RCSwitch::nReceivedValue = 0; +volatile unsigned long long RCSwitch::nReceiveProtocolMask; volatile unsigned int RCSwitch::nReceivedBitlength = 0; volatile unsigned int RCSwitch::nReceivedDelay = 0; volatile unsigned int RCSwitch::nReceivedProtocol = 0; @@ -146,7 +146,6 @@ const unsigned int RCSwitch::nSeparationLimit = 2600; // 4300 default // should be set to the minimum value of pulselength * the sync signal unsigned int RCSwitch::timings[RCSWITCH_MAX_CHANGES]; unsigned int RCSwitch::buftimings[4]; -uint64_t_t RCSwitch::enabled_protocol_mask; #endif RCSwitch::RCSwitch() { @@ -157,10 +156,11 @@ RCSwitch::RCSwitch() { this->nReceiverInterrupt = -1; this->setReceiveTolerance(60); RCSwitch::nReceivedValue = 0; - RCSwitch::enabled_protocol_mask.value = (1ULL << numProto)-1 ;//pow(2,numProto)-1; + RCSwitch::nReceiveProtocolMask = (1ULL << numProto)-1; //pow(2,numProto)-1; #endif } -uint8_t RCSwitch::getNumProtos(){ + +uint8_t RCSwitch::getNumProtos() { return numProto; } /** @@ -214,8 +214,12 @@ void RCSwitch::setRepeatTransmit(int nRepeatTransmit) { void RCSwitch::setReceiveTolerance(int nPercent) { RCSwitch::nReceiveTolerance = nPercent; } + +void RCSwitch::setReceiveProtocolMask(unsigned long long mask) { + RCSwitch::nReceiveProtocolMask = mask; +} #endif - + /** * Enable transmissions @@ -418,7 +422,7 @@ char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus if ( nFamily < 0 || nFamily > 15 || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) { return 0; } - + // encode the family into four bits sReturn[nReturnPos++] = (nFamily & 1) ? 'F' : '0'; sReturn[nReturnPos++] = (nFamily & 2) ? 'F' : '0'; @@ -454,7 +458,7 @@ char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus * * Source: http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/ * - * @param sGroup Name of the switch group (A..D, resp. a..d) + * @param sGroup Name of the switch group (A..D, resp. a..d) * @param nDevice Number of the switch itself (1..3) * @param bStatus Whether to switch on (true) or off (false) * @@ -623,7 +627,7 @@ void RCSwitch::send(unsigned long long code, unsigned int length) { void RCSwitch::transmit(HighLow pulses) { uint8_t firstLogicLevel = (this->protocol.invertedSignal) ? LOW : HIGH; uint8_t secondLogicLevel = (this->protocol.invertedSignal) ? HIGH : LOW; - + if (pulses.high > 0) { digitalWrite(this->nTransmitterPin, firstLogicLevel); delayMicroseconds( this->protocol.pulseLength * pulses.high); @@ -738,7 +742,7 @@ bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCoun // nReceiveTolerance = 60 // допустимое отклонение длительностей импульсов на 60 % const unsigned int delayTolerance = delay * RCSwitch::nReceiveTolerance / 100; - + // 0 - sync перед preamble или data // BeginData - сдвиг на 1 или 2 от sync к preamble/data // FirstTiming - сдвиг на preamble к header @@ -815,7 +819,7 @@ void RECEIVE_ATTR RCSwitch::handleInterrupt() { changeCount == 156 || (diff(RCSwitch::buftimings[3], RCSwitch::buftimings[2]) < 50 && diff(RCSwitch::buftimings[2], RCSwitch::buftimings[1]) < 50 && - changeCount > 25)) { + changeCount > 25)) { // принят длинный импульс продолжительностью более nSeparationLimit (4300) // A long stretch without signal level change occurred. This could // be the gap between two transmission. @@ -825,7 +829,7 @@ void RECEIVE_ATTR RCSwitch::handleInterrupt() { diff(RCSwitch::buftimings[2], RCSwitch::timings[2]) < 50 && diff(RCSwitch::buftimings[1], RCSwitch::timings[3]) < 50 && changeCount > 25)) { - // если его длительность отличается от первого импульса, + // если его длительность отличается от первого импульса, // который приняли раньше, менее чем на +-200 (исходно 200) // то считаем это повторным пакетом и игнорируем его // This long signal is close in length to the long signal which @@ -840,7 +844,7 @@ void RECEIVE_ATTR RCSwitch::handleInterrupt() { if (repeatCount == 1) { unsigned long long thismask = 1; for(unsigned int i = 1; i <= numProto; i++) { - if(enabled_protocol_mask.value & thismask){ + if (RCSwitch::nReceiveProtocolMask & thismask) { if (receiveProtocol(i, changeCount)) { // receive succeeded for protocol i break; @@ -863,7 +867,7 @@ void RECEIVE_ATTR RCSwitch::handleInterrupt() { changeCount = 4; } } - + // detect overflow if (changeCount >= RCSWITCH_MAX_CHANGES) { changeCount = 0; @@ -872,10 +876,10 @@ void RECEIVE_ATTR RCSwitch::handleInterrupt() { // заносим в массив длительность очередного принятого импульса if (changeCount > 0 && duration < 100) { // игнорируем шумовые всплески менее 100 мкс - RCSwitch::timings[changeCount-1] += duration; + RCSwitch::timings[changeCount-1] += duration; } else { RCSwitch::timings[changeCount++] = duration; } - lastTime = time; + lastTime = time; } #endif diff --git a/lib/lib_rf/rc-switch/src/RCSwitch.h b/lib/lib_rf/rc-switch/src/RCSwitch.h index 92ef61f46..613d654d7 100644 --- a/lib/lib_rf/rc-switch/src/RCSwitch.h +++ b/lib/lib_rf/rc-switch/src/RCSwitch.h @@ -10,7 +10,7 @@ - Frank Oltmanns / .(at)gmail(dot)com - Max Horn / max(at)quendi(dot)de - Robert ter Vehn / .(at)gmail(dot)com - + Project home: https://github.com/sui77/rc-switch/ This library is free software; you can redistribute it and/or @@ -61,22 +61,11 @@ // Для keeloq нужно увеличить RCSWITCH_MAX_CHANGES до 23+1+66*2+1=157 #define RCSWITCH_MAX_CHANGES 67 // default 67 -typedef union __uint64 -{ - uint64_t value; - struct - { - uint32_t low32; - uint32_t high32; - - } longs; -} uint64_t_t; - class RCSwitch { public: RCSwitch(); - + void switchOn(int nGroupNumber, int nSwitchNumber); void switchOff(int nGroupNumber, int nSwitchNumber); void switchOn(const char* sGroup, int nSwitchNumber); @@ -91,7 +80,7 @@ class RCSwitch { void sendTriState(const char* sCodeWord); void send(unsigned long long code, unsigned int length); void send(const char* sCodeWord); - + #if not defined( RCSwitchDisableReceiving ) void enableReceive(int interrupt); void enableReceive(); @@ -105,15 +94,15 @@ class RCSwitch { unsigned int getReceivedProtocol(); unsigned int* getReceivedRawdata(); uint8_t getNumProtos(); - static uint64_t_t enabled_protocol_mask; //perhaps need function to change because used in interrupt #endif - + void enableTransmit(int nTransmitterPin); void disableTransmit(); void setPulseLength(int nPulseLength); void setRepeatTransmit(int nRepeatTransmit); #if not defined( RCSwitchDisableReceiving ) void setReceiveTolerance(int nPercent); + void setReceiveProtocolMask(unsigned long long mask); #endif /** @@ -177,32 +166,28 @@ class RCSwitch { static void handleInterrupt(); static bool receiveProtocol(const int p, unsigned int changeCount); int nReceiverInterrupt; - #endif - int nTransmitterPin; int nRepeatTransmit; - Protocol protocol; #if not defined( RCSwitchDisableReceiving ) static int nReceiveTolerance; volatile static unsigned long long nReceivedValue; + volatile static unsigned long long nReceiveProtocolMask; volatile static unsigned int nReceivedBitlength; volatile static unsigned int nReceivedDelay; volatile static unsigned int nReceivedProtocol; const static unsigned int nSeparationLimit; - /* + /* * timings[0] contains sync timing, followed by a number of bits */ static unsigned int timings[RCSWITCH_MAX_CHANGES]; // буфер длительностей последних четырех пакетов, [0] - последний static unsigned int buftimings[4]; - - #endif - + }; #endif diff --git a/tasmota/i18n.h b/tasmota/i18n.h index 807f1d5c6..b84ce4265 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -221,8 +221,7 @@ #define D_LOG_SOME_SETTINGS_RESET "Some settings have been reset" -// Commands tasmota.ino - +// Commands tasmota.ino #define D_CMND_BACKLOG "Backlog" #define D_CMND_DELAY "Delay" #define D_CMND_NODELAY "NoDelay" diff --git a/tasmota/settings.h b/tasmota/settings.h index c9bddc06f..02dd5cba3 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -642,9 +642,14 @@ struct { uint16_t shd_warmup_brightness; // F5C uint8_t shd_warmup_time; // F5E - uint8_t free_f5e[84]; // F5E - Decrement if adding new Setting variables just above and below + uint8_t free_f5e[72]; // F5E - Decrement if adding new Setting variables just above and below // Only 32 bit boundary variables below + + uint64_t rf_protocol_mask; // FA8 + + uint32_t free_fb0[1]; // FB0 + SysBitfield5 flag5; // FB4 uint16_t pulse_counter_debounce_low; // FB8 uint16_t pulse_counter_debounce_high; // FBA diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index da7ff3a1c..4b9e21839 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -43,6 +43,7 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix "|Info|" D_CMND_TOUCH_CAL "|" D_CMND_TOUCH_THRES "|" D_CMND_TOUCH_NUM "|" D_CMND_CPU_FREQUENCY "|" D_CMND_WIFI #endif // ESP32 ; + void (* const TasmotaCommand[])(void) PROGMEM = { &CmndBacklog, &CmndDelay, &CmndPower, &CmndStatus, &CmndState, &CmndSleep, &CmndUpgrade, &CmndUpgrade, &CmndOtaUrl, &CmndSeriallog, &CmndRestart, &CmndPowerOnState, &CmndPulsetime, &CmndBlinktime, &CmndBlinkcount, &CmndSavedata, diff --git a/tasmota/xdrv_17_rcswitch.ino b/tasmota/xdrv_17_rcswitch.ino index fad417d8f..24d294c48 100644 --- a/tasmota/xdrv_17_rcswitch.ino +++ b/tasmota/xdrv_17_rcswitch.ino @@ -28,17 +28,17 @@ #define D_JSON_RF_DATA "Data" #define D_CMND_RFSEND "RFSend" +#define D_CMND_RFPROTOCOL "RfProtocol" + #define D_JSON_RF_PULSE "Pulse" #define D_JSON_RF_REPEAT "Repeat" -#define D_CMND_RFRXPROTOCOL "RfRxProtocol" #define D_JSON_NONE_ENABLED "None Enabled" - -const char kRfCommands[] PROGMEM = "|" D_CMND_RFSEND "|" D_CMND_RFRXPROTOCOL; // No prefix - +const char kRfCommands[] PROGMEM = "|" // No prefix + D_CMND_RFSEND "|" D_CMND_RFPROTOCOL; void (* const RfCommands[])(void) PROGMEM = { - &CmndRfSend,&CmndRfRxProtocol }; + &CmndRfSend, &CmndRfProtocol }; #include @@ -48,8 +48,7 @@ RCSwitch mySwitch = RCSwitch(); uint32_t rf_lasttime = 0; -void RfReceiveCheck(void) -{ +void RfReceiveCheck(void) { if (mySwitch.available()) { unsigned long data = mySwitch.getReceivedValue(); @@ -80,82 +79,77 @@ void RfReceiveCheck(void) } } -void RfInit(void) -{ +void RfInit(void) { if (PinUsed(GPIO_RFSEND)) { mySwitch.enableTransmit(Pin(GPIO_RFSEND)); } if (PinUsed(GPIO_RFRECV)) { pinMode( Pin(GPIO_RFRECV), INPUT); mySwitch.enableReceive(Pin(GPIO_RFRECV)); - GetMaskFromSettings(); + if (!Settings.rf_protocol_mask) { + Settings.rf_protocol_mask = (1ULL << mySwitch.getNumProtos()) -1; + } + mySwitch.setReceiveProtocolMask(Settings.rf_protocol_mask); } } -void GetMaskFromSettings(){ - mySwitch.enabled_protocol_mask.longs.high32 = Settings.ex_adc_param1 ; - mySwitch.enabled_protocol_mask.longs.low32 = Settings.ex_adc_param2 ; -} -void SaveMaskToSettings(){ - Settings.ex_adc_param1 = mySwitch.enabled_protocol_mask.longs.high32; - Settings.ex_adc_param2 = mySwitch.enabled_protocol_mask.longs.low32; - SettingsSave(1); -} + /*********************************************************************************************\ * Commands \*********************************************************************************************/ -void CmndRfRxProtocol(void){ - if(!PinUsed(GPIO_RFRECV))return; +void CmndRfProtocol(void) { + if (!PinUsed(GPIO_RFRECV)) { return; } + // AddLog_P(LOG_LEVEL_INFO, PSTR("RFR:CmndRfRxProtocol:: index:%d usridx:%d data_len:%d data:\"%s\""),XdrvMailbox.index, XdrvMailbox.usridx, XdrvMailbox.data_len,XdrvMailbox.data); - + uint64_t thisdat; - if (XdrvMailbox.usridx==1) { - if(XdrvMailbox.payload >=0){ - thisdat = (1ULL << (XdrvMailbox.index-1) ); - if(XdrvMailbox.payload &1){ - mySwitch.enabled_protocol_mask.value |= thisdat; - }else{ - mySwitch.enabled_protocol_mask.value &= ~thisdat; + if (1 == XdrvMailbox.usridx) { + if (XdrvMailbox.payload >= 0) { + thisdat = (1ULL << (XdrvMailbox.index -1)); + if (XdrvMailbox.payload &1) { + Settings.rf_protocol_mask |= thisdat; + } else { + Settings.rf_protocol_mask &= ~thisdat; + } + } + else if (XdrvMailbox.data_len > 0) { + return; // Not a number + } + } else { + if (XdrvMailbox.data_len > 0) { + if ('a' == XdrvMailbox.data[0]) { + Settings.rf_protocol_mask = (1ULL << mySwitch.getNumProtos()) -1; + } else { + thisdat = strtoull(XdrvMailbox.data, nullptr, 0); + if ((thisdat > 0) || ('0' == XdrvMailbox.data[0])) { + Settings.rf_protocol_mask = thisdat; + } else { + return; // Not a number + } } - SaveMaskToSettings(); - }else if(XdrvMailbox.data_len > 0) return; // not a number - }else{ - if(XdrvMailbox.data_len >0){ - if(XdrvMailbox.data[0]=='a'){ - mySwitch.enabled_protocol_mask.value= (1ULL << mySwitch.getNumProtos())-1 ; - SaveMaskToSettings(); - }else{ - thisdat = strtoull(XdrvMailbox.data,nullptr, 0); - if(thisdat>0 || XdrvMailbox.data[0]=='0' ){ - mySwitch.enabled_protocol_mask.value = thisdat; - SaveMaskToSettings(); - }else return; // not a number - } - } } -// AddLog_P(LOG_LEVEL_INFO, PSTR("RFR:CmndRfRxProtocol:: Start responce")); - ResponseClear(); - ResponseAppend_P(PSTR("{\"" D_CMND_RFRXPROTOCOL "\":")); - ResponseAppend_P(PSTR("\"")); + mySwitch.setReceiveProtocolMask(Settings.rf_protocol_mask); +// AddLog_P(LOG_LEVEL_INFO, PSTR("RFR: CmndRfProtocol:: Start responce")); + Response_P(PSTR("{\"" D_CMND_RFPROTOCOL "\":\"")); bool gotone = false; - thisdat=1; - for (int i=0;i