Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rpn: rfbridge rules #2302

Merged
merged 22 commits into from
Aug 26, 2020
Merged

rpn: rfbridge rules #2302

merged 22 commits into from
Aug 26, 2020

Conversation

mcspr
Copy link
Collaborator

@mcspr mcspr commented Jul 16, 2020

Testing #2274

Some new operators:

  • rfb_match to trigger something on the exact N hits of the code
    top argument is the code string, 2nd is protocol index, 3rd is number to compare with how much this code have been seen recently
  • rfb_sequence to trigger something in specific sequence. needs 2 pairs of protocol number + raw code string.

For example, using 'stock' RFBridge, where we only have a single protocol:

1u 0u "123456" rfb_match millis &movement =

Meaning, we should set 'movement' variable to the current device's time when we see 00123456 the very first time.
Or,

2u 0u "567891" rfb_match 2 0 relay

To toggle 1st relay (index 0) when we receive the code twice

We also finally receive MQTT variables on connection by defaulting mqttSkipTime / MQTT_SKIP_TIME to 0. See topics in the rules section.

cc @davebuk from #2296

code/espurna/rpnrules.cpp Outdated Show resolved Hide resolved
code/espurna/rpnrules.cpp Outdated Show resolved Hide resolved
code/espurna/rpnrules.cpp Outdated Show resolved Hide resolved
@mcspr
Copy link
Collaborator Author

mcspr commented Jul 17, 2020

Regarding operator's syntax - it simply stops execution, so anything to the right of it is silently dropped and we jump to the next rules string. Originally, state was declared as variable - $relay0, $temperature0 etc., - but then we would need to have additional operator not or eq to a specific state we want. So, one less thing to type out.

@davebuk
Copy link
Contributor

davebuk commented Jul 24, 2020

I have built a firmware including RPN rules using your code from: 451a413

It builds but I can't get access to the initial webUI. During build I get:

Compiling .pio\build\db-wemos-pzemv3-rf\src\rpc.cpp.o
espurna\relay.cpp: In function 'void _relaySetupAdhoc()':
espurna\relay.cpp:1475:20: warning: unused variable 'pin' [-Wunused-variable]
         const auto pin = _relayPin(id);

I don't know if that would cause the firmware to not run correctly.

Build config is:

#elif defined(DB_WEMOS_RF)

    #define MANUFACTURER            "WEMOS"
    #define DEVICE                  "RF"
    #define RELAY_PROVIDER          RELAY_PROVIDER_RFBRIDGE

    // Number of virtual switches
    #ifndef DUMMY_RELAY_COUNT
    #define DUMMY_RELAY_COUNT   8
    #endif
	
    // My config
    #define ALEXA_SUPPORT           0
    #define DOMOTICZ_SUPPORT        0
    #define HOMEASSISTANT_SUPPORT   0
    #define THINGSPEAK_SUPPORT      0
    #define RPN_RULES_SUPPORT       1
	
    // Buttons
    #define BUTTON1_PIN         	0    // D3
    #define BUTTON1_CONFIG      	BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH | BUTTON_SET_PULLUP
	
    // LEDs
    #define LED1_PIN            	2 // D4
    #define LED1_PIN_INVERSE    	1
	
	
    // RF Support
    #define RF_SUPPORT              1
    #define RFB_DIRECT              1
    #define RFB_RX_PIN              5 // D1

@mcspr
Copy link
Collaborator Author

mcspr commented Jul 24, 2020

Warning points to the exact issue. Enabling rfbridge relay provider is broken atm :/

diff --git a/code/espurna/relay.cpp b/code/espurna/relay.cpp
index eca66fc5..ab6f1169 100644
--- a/code/espurna/relay.cpp
+++ b/code/espurna/relay.cpp
@@ -1473,15 +1473,13 @@ void _relaySetupAdhoc() {

     for (unsigned char id = 0; id < RelaysMax; ++id) {
         const auto pin = _relayPin(id);
-        #if (RELAY_PROVIDER == RELAY_PROVIDER_RELAY) || (RELAY_PROVIDER == RELAY_PROVIDER_LIGHT)
-            if (!gpioValid(pin)) {
-                break;
-            }
-        #elif (RELAY_PROVIDER == RELAY_PROVIDER_MCP23S08)
+        #if (RELAY_PROVIDER == RELAY_PROVIDER_MCP23S08)
             if (!mcpGpioValid(pin)) {
+        #else
+            if (!gpioValid(pin)) {
+        #endif
                 break;
             }
-        #endif

         _relays.emplace_back(
             std::make_unique<gpio_type>(_relayPin(id)),

@mcspr
Copy link
Collaborator Author

mcspr commented Jul 24, 2020

Re: if the intent is to use rules and not to use relays to send codes, just keep the default provider setting. dummy relay count setting will still work

@davebuk
Copy link
Contributor

davebuk commented Jul 24, 2020

The intent is to either have espurna publish the received 433MHz code as an MQTT topic to allow openHAB to do something when it sees that code or, have a dummy relay toggle based on the 433MHz code. The MQTT topic for that relay would be the openHAB trigger instead.

@mcspr
Copy link
Collaborator Author

mcspr commented Jul 24, 2020

RELAY_PROVIDER_RFBRIDGE only handles the sending. Rfbridge code handles the receiving part independently and tries to toggle things when rfbON# / rfbOFF# keys match. Btw, make sure it isn't configured like that, rules will cause a conflict. See RF panel / those keys and delete them.

@davebuk
Copy link
Contributor

davebuk commented Jul 24, 2020

I'll comment out the #define RELAY_PROVIDER part and the #idefine DUMMY_RELAY_COUNT 8 sections and try again.

@davebuk
Copy link
Contributor

davebuk commented Jul 24, 2020

Building with:

#elif defined(DB_WEMOS_RF)

    #define MANUFACTURER            "WEMOS"
    #define DEVICE                  "RF"

    // My config
    #define ALEXA_SUPPORT           0
    #define DOMOTICZ_SUPPORT        0
    #define HOMEASSISTANT_SUPPORT   0
    #define THINGSPEAK_SUPPORT      0
    #define RPN_RULES_SUPPORT       1
	
    // Buttons
    #define BUTTON1_PIN         	0    // D3
    #define BUTTON1_CONFIG      	BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH | BUTTON_SET_PULLUP
	
    // LEDs
    #define LED1_PIN            	2 // D4
    #define LED1_PIN_INVERSE    	1
	
    // RF Support
    #define RF_SUPPORT              1
    #define RFB_DIRECT              1
    #define RFB_RX_PIN              5 // D1

I have the following output:

[048349] [RF] Received code: 00D7410E
[048349] [RF] Action 0xA4
[048349] [RF] Received message 'C00101C31800D7410E'
[048350] [RF] Trying to match code D7410E
[048353] [MQTT] Sending SensorRF/rfin => C00101C31800D7410E (PID 63)
[048359] [RPN] new code: 00D7410E
[048363] [MQTT] Publish ACK for PID 63
[048923] [RF] Received code: 00D7410E
[048923] [RF] Action 0xA4
[048924] [RF] Received message 'C00101C21800D7410E'
[048924] [RF] Trying to match code D7410E
[048927] [MQTT] Sending SensorRF/rfin => C00101C21800D7410E (PID 64)
[048932] [RPN] refresh code=00D7410E hits=2 last=1048932
[048939] [MQTT] Publish ACK for PID 64

I'll have to get my head around RPN rules now to create a rule that either process the second code and do something via MQTT or add the dummy relays back in and switch those using RPN rules.

@mcspr
Copy link
Collaborator Author

mcspr commented Jul 24, 2020

2 "00D7410E" rfb_match "topic" "message" mqtt_send

?

Translated as: compare latest received code with "00D7410E" and make sure it has hits=2 (see [RPN] log). When condition matches, mqtt_send sends text data.
The idea is to avoid if / else & variables, but simply don't continue the rule if rfb_match does not 'match' the code

@mcspr
Copy link
Collaborator Author

mcspr commented Jul 25, 2020

As another example, check this out in terminal. Running multiple times it should send either 0 or 1 to the "test" topic (note the escaped quotes)

rpn.test "\"test\" &test not &test = \"1\" \"0\" ifn mqtt_send"

&var not &var = is the main 'magic', toggling 'test' variable between true and false whenever executed (default state is false, so first time this runs $var would become true). ifn then takes the value and chooses between "1" and "0", which becomes the message text.

Note the slightly different syntax for variables, using & instead of $ we then could use the = operator and change the 'test' value right in the expression.

rpn.test "\"test\" &test not &test = mqtt_send"

Or, another option use built-in stringification of the boolean value into "true" or "false" (as mqtt_send will automatically convert both input values into strings)

edit3: updated for 0.23.0


// hits == 1 is a single click, hits == 5 is long click
// we sort-of can distinguish single and double via timestamp, but it has a **very** unreliable timing
if ((*result).hits > hits.toUint()) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check and the one below need to be slightly reworked to only trigger themselves when 'hits' stayed the same for a specific interval. After that, we could throw out the code instead of keeping it.

Another apparent issue with the check is eq vs. gt difference, we must have the exact number of hits or rule does not work. Perhaps the operator could push 'hits' on the stack when value stabilizes, and comparison could happen in the expression (including greater-than, greater-than-or-equal, etc.)

Copy link
Collaborator Author

@mcspr mcspr Jul 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note-to-self:

Yep, seems like a solution. So:

  • broker from rf keeps sending codes as-is
  • add additional task that checks if code had been stable for long enough, flag it as such and trigger rules
  • rpn_match will only work with flagged codes, pushing number of hits
  • after rules are done, code is removed from tracking (for the time being)

Other option was to keep checking it in the rule itself, simply making _rpn_run=true after match did not work. It is probably slower though

@davebuk
Copy link
Contributor

davebuk commented Jul 28, 2020

2 "00D7410E" rfb_match "topic" "message" mqtt_send

?

Translated as: compare latest received code with "00D7410E" and make sure it has hits=2 (see [RPN] log). When condition matches, mqtt_send sends text data.
The idea is to avoid if / else & variables, but simply don't continue the rule if rfb_match does not 'match' the code

Using 2 "00D7410E" rfb_match "topic" "closed" mqtt_send and 2 "00D7410A" rfb_match "topic" "open" mqtt_send I get the follow. I don't think its counting the hits as [MQTT] Sending topic => closed gets sent after the first trigger.

[360770] [RF] Received code: 00D7410E
[360771] [RF] Action 0xA4
[360771] [RF] Received message 'C00101C21800D7410E'
[360771] [RF] Trying to match code D7410E
[360775] [MQTT] Sending SensorRF/rfin => C00101C21800D7410E (PID 58)
[360779] [RPN] new code: 00D7410E
[360784] [MQTT] Publish ACK for PID 58
[360802] [MQTT] Sending topic => closed (PID 59)
[360810] [MQTT] Publish ACK for PID 59
[361353] [RF] Received code: 00D7410E
[361354] [RF] Action 0xA4
[361354] [RF] Received message 'C00101C21800D7410E'
[361354] [RF] Trying to match code D7410E
[361358] [MQTT] Sending SensorRF/rfin => C00101C21800D7410E (PID 60)
[361363] [RPN] refresh code=00D7410E hits=2 last=361363
[361369] [MQTT] Publish ACK for PID 60
[371234] [RF] Received code: 00D7410A
[371234] [RF] Action 0xA4
[371234] [RF] Received message 'C00101C21800D7410A'
[371235] [RF] Trying to match code D7410A
[371238] [MQTT] Sending SensorRF/rfin => C00101C21800D7410A (PID 61)
[371243] [RPN] new code: 00D7410A
[371249] [MQTT] Publish ACK for PID 61
[371262] [MQTT] Sending topic => open (PID 62)
[371267] [MQTT] Publish ACK for PID 62
[371822] [RF] Received code: 00D7410A
[371822] [RF] Action 0xA4
[371823] [RF] Received message 'C00101C21800D7410A'
[371823] [RF] Trying to match code D7410A
[371826] [MQTT] Sending SensorRF/rfin => C00101C21800D7410A (PID 63)
[371831] [RPN] refresh code=00D7410A hits=2 last=371831
[371837] [MQTT] Publish ACK for PID 63

@davebuk
Copy link
Contributor

davebuk commented Jul 28, 2020

As another example, check this out in terminal. Running multiple times it should send either 0 or 1 to the "test" topic (note the escaped quotes)

rpn.test "\"test\" &test not &test = \"1\" \"0\" ifn mqtt_send"

&var not &var = is the main 'magic', toggling 'test' variable between true and false whenever executed (default state is false, so first time this runs $var would become true). ifn then takes the value and chooses between "1" and "0", which becomes the message text.

Note the slightly different syntax for variables, using & instead of $ we then could use the = operator and change the 'test' value right in the expression.

rpn.test "\"test\" &test not &test = mqtt_send"

Or, another option use built-in stringification of the boolean value into "true" or "false" (as mqtt_send will automatically convert both input values into strings)

edit3: updated for 0.23.0

Is this test using the string "test" as a boolean true/false change trigger? I tried with the rule set to 2 "00D7410E" rfb_match "topic" "test" mqtt_send and I pasted separately the two rpn.test lines into the terminal but I don't get any MQTT messages other than [MQTT] Sending SensorRF/rfin => C00101C21800D7410A

@mcspr
Copy link
Collaborator Author

mcspr commented Jul 29, 2020

Current implementation of 'rfb_match' marks code as used, so multiple rules or calling rpn.test with the same code won't work (why I wrote that note-to-self to fix that). Another issue is timing, since it won't see any matches outside of 2 second window, so your test won't ever reach "topic" "test" mqtt_send

Boolean value comes from 'test' variable. e.g. try running rpn.test with:

  • $test
  • $test not
    Both won't work, because there is no variable named 'test'
  • &test
    When variable does not exist yet, & will create it and set it to null. rpn.vars won't show it afterwards, as variable will be deleted as 'unused' when we clear the stack (which always happens after each rule execution / rpn.test)
  • &test not
    Converting null into boolean null becomes false.
  • "1" &test =
    Will assign "1" to the variable named 'test' and rpn.vars will show it now. Note that stack now contains "1", too, because &test is kept on the stack and trying to read it produces the updated value.

@davebuk
Copy link
Contributor

davebuk commented Jul 31, 2020

Testing version 403e0c8.

I thought the rpn.test did something with the values from the rfb_match output. I can see now that its just a test.
rpn.test "\"test\" &test not &test = \"1\" \"0\" ifn mqtt_send" sent twice gives:

[530061] [RPN] Running ""test" &test not &test = "1" "0" ifn mqtt_send"
[530064] [MQTT] Sending test => 0 (PID 62)
[530065] [RPN] Stack:
[530065]       (empty)
+OK
[530070] [MQTT] Publish ACK for PID 62
[532561] [WEBSOCKET] Requested action: dbgcmd
[532564] [RPN] Running ""test" &test not &test = "1" "0" ifn mqtt_send"
[532568] [MQTT] Sending test => 1 (PID 63)
[532568] [RPN] Stack:
[532568]       (empty)
+OK
[532574] [MQTT] Publish ACK for PID 63

and rpn.test "\"test\" &test not &test = mqtt_send" twice gives:

[611646] [RPN] Running ""test" &test not &test = mqtt_send"
[611649] [MQTT] Sending test => false (PID 66)
[611650] [RPN] Stack:
[611650]       (empty)
+OK
[611655] [MQTT] Publish ACK for PID 66
[614248] [WEBSOCKET] Requested action: dbgcmd
[614255] [RPN] Running ""test" &test not &test = mqtt_send"
[614258] [MQTT] Sending test => true (PID 67)
[614259] [RPN] Stack:
[614259]       (empty)
+OK
[614265] [MQTT] Publish ACK for PID 67

@davebuk
Copy link
Contributor

davebuk commented Jul 31, 2020

I thought the way the rule worked was to only mqtt_send if hits are >2. Is it actually, mqtt_send if the rule code matches, but then don't send any more mqtt_send messages if the hits are >2?

With respect to timing, if I use my two rules for monitoring the sensor as closed and open in the order below in the rules section (I don't know if there is a preferred order for the rules ):
2 "00D7410E" rfb_match "topic" "closed" mqtt_send
and
2 "00D7410A" rfb_match "topic" "open" mqtt_send
the closed is sent via MQTT before the open even though the sensor has opened then closed. If I wait more than four seconds before closing the sensor, it reports them in the correct order.
1 second gap

[793943] [RF] Received code: 00D7410A
[793944] [RF] Action 0xA4
[793944] [RF] Received message 'C00101C61800D7410A'
[793945] [RF] Trying to match code D7410A
[793952] [MQTT] Sending SensorRF/rfin => C00101C61800D7410A (PID 351)
[793953] [RPN] new code: 00D7410A
[793957] [MQTT] Publish ACK for PID 351
[793976] [MQTT] Sending topic => open (PID 352)
[793982] [MQTT] Publish ACK for PID 352
[794528] [RF] Received code: 00D7410A
[794529] [RF] Action 0xA4
[794530] [RF] Received message 'C00101C21800D7410A'
[794530] [RF] Trying to match code D7410A
[794536] [MQTT] Sending SensorRF/rfin => C00101C21800D7410A (PID 353)
[794539] [RPN] refresh code=00D7410A hits=2 last=1794538
[794548] [MQTT] Publish ACK for PID 353
[795221] [RF] Received code: 00D7410E
[795222] [RF] Action 0xA4
[795222] [RF] Received message 'C00101C31800D7410E'
[795223] [RF] Trying to match code D7410E
[795230] [MQTT] Sending SensorRF/rfin => C00101C31800D7410E (PID 354)
[795232] [RPN] new code: 00D7410E
[795236] [MQTT] Publish ACK for PID 354
[795250] [MQTT] Sending topic => closed (PID 355)
[795253] [MQTT] Sending topic => open (PID 356)
[795260] [MQTT] Publish ACK for PID 355
[795265] [MQTT] Publish ACK for PID 356
[795808] [RF] Received code: 00D7410E
[795809] [RF] Action 0xA4
[795809] [RF] Received message 'C00101C41800D7410E'
[795809] [RF] Trying to match code D7410E
[795816] [MQTT] Sending SensorRF/rfin => C00101C41800D7410E (PID 357)
[795817] [RPN] refresh code=00D7410E hits=2 last=1795817
[795823] [MQTT] Publish ACK for PID 357

4 second gap

[824910] [RF] Received code: 00D7410A
[824911] [RF] Action 0xA4
[824911] [RF] Received message 'C00101C21800D7410A'
[824911] [RF] Trying to match code D7410A
[824918] [MQTT] Sending SensorRF/rfin => C00101C21800D7410A (PID 380)
[824919] [RPN] new code: 00D7410A
[824926] [MQTT] Publish ACK for PID 380
[824940] [MQTT] Sending topic => open (PID 381)
[824946] [MQTT] Publish ACK for PID 381
[825490] [RF] Received code: 00D7410A
[825490] [RF] Action 0xA4
[825491] [RF] Received message 'C00101C31800D7410A'
[825491] [RF] Trying to match code D7410A
[825498] [MQTT] Sending SensorRF/rfin => C00101C31800D7410A (PID 382)
[825499] [RPN] refresh code=00D7410A hits=2 last=1825499
[825506] [MQTT] Publish ACK for PID 382
[827924] [RF] Received code: 00D7410E
[827925] [RF] Action 0xA4
[827925] [RF] Received message 'C00101C41800D7410E'
[827926] [RF] Trying to match code D7410E
[827932] [MQTT] Sending SensorRF/rfin => C00101C41800D7410E (PID 383)
[827934] [RPN] new code: 00D7410E
[827938] [MQTT] Publish ACK for PID 383
[827956] [MQTT] Sending topic => closed (PID 384)
[827963] [MQTT] Publish ACK for PID 384
[828507] [RF] Received code: 00D7410E
[828508] [RF] Action 0xA4
[828509] [RF] Received message 'C00101C31800D7410E'
[828509] [RF] Trying to match code D7410E
[828515] [MQTT] Sending SensorRF/rfin => C00101C31800D7410E (PID 385)
[828517] [RPN] refresh code=00D7410E hits=2 last=1828517
[828523] [MQTT] Publish ACK for PID 385

@mcspr
Copy link
Collaborator Author

mcspr commented Aug 1, 2020

I thought the way the rule worked was to only mqtt_send if hits are >2. Is it actually, mqtt_send if the rule code matches, but then don't send any more mqtt_send messages if the hits are >2?

That was a typo :/ I was away from the original device, so I must've uploaded the correct version there (haven't heard complaints yet:). Condition indeed was if "new code hits" < "hits set by operator" then do things, so I've replaced it with the exact match, as intended.

rpnRule0 => "3 "00123456" rfb_match "hello world" log"

Prints "hello world" every 3rd click of remote b/c code 'hits' reset back to 0 on the match.

@mcspr
Copy link
Collaborator Author

mcspr commented Aug 2, 2020

Some experimental stuff to support matching same code in multiple rules.

  • <time> <hits> <code> rfb_match_wait accepting additional param of wait-time.
get rpnRule0 rpnRule1
> rpnRule0 => 2000 3 0u "123456" rfb_match_wait "--- three" dbgmsg
> rpnRule1 => 2000 1 0u "123456" rfb_match_wait "--- one" dbgmsg

Will run a 2 second timer when code has at least N hits and continue only when timer had finished. Ordering is important though, so higher hits count needs to go first. After execution, it will 'eat' the code and force the rule after it to fail.

  • <proto> <code> rfb_info dumps hits and last time (in that order and ofc it depends that no matcher uses this code)
  • <proto> <code> rfb_pop to remove the code from tracking

I've forcibly rebased the branch with the current dev, so... git-pull probably won't work. It depends on how you 'get' the branch. Short example when using remotes directly:

$ git fetch <mcspr-remote> rpn/rfb-codes-plus
$ git reset --hard FETCH_HEAD

@davebuk
Copy link
Contributor

davebuk commented Aug 3, 2020

I use Pull (REBASE) option in PlatformIO, now I am running 245723f

> rpnRule0 => "2 "00D7410E" rfb_match "topic" "CLOSED" mqtt_send"
> rpnRule1 => "2 "00D7410A" rfb_match "topic" "OPEN" mqtt_send"

Using the same rules as before (shown above) which looked for two different codes, I now correctly get the OPEN and CLOSED after the second rfb_match. It also works if I quickly open then close the RF sensor within 1 second :-)

[287061] [RF] Received code: 00D7410A
[287062] [RF] Action 0xA4
[287062] [RF] Received message 'C00101C21800D7410A'
[287063] [RF] Trying to match code D7410A
[287069] [MQTT] Sending SensorRF/rfin => C00101C21800D7410A (PID 713)
[287071] [RPN] new code: 00D7410A
[287076] [MQTT] Publish ACK for PID 713
[287638] [RF] Received code: 00D7410A
[287638] [RF] Action 0xA4
[287638] [RF] Received message 'C00101C21800D7410A'
[287639] [RF] Trying to match code D7410A
[287645] [MQTT] Sending SensorRF/rfin => C00101C21800D7410A (PID 714)
[287647] [RPN] refresh code=00D7410A hits=2 last=8287647
[287653] [MQTT] Publish ACK for PID 714
[287672] [MQTT] Sending topic => OPEN (PID 715)
[287679] [MQTT] Publish ACK for PID 715
[288894] [RF] Received code: 00D7410E
[288895] [RF] Action 0xA4
[288895] [RF] Received message 'C00101C31800D7410E'
[288895] [RF] Trying to match code D7410E
[288902] [MQTT] Sending SensorRF/rfin => C00101C31800D7410E (PID 716)
[288903] [RPN] new code: 00D7410E
[288924] [MQTT] Publish ACK for PID 716
[289477] [RF] Received code: 00D7410E
[289478] [RF] Action 0xA4
[289478] [RF] Received message 'C00101C21800D7410E'
[289479] [RF] Trying to match code D7410E
[289485] [MQTT] Sending SensorRF/rfin => C00101C21800D7410E (PID 717)
[289487] [RPN] refresh code=00D7410E hits=2 last=8289487
[289493] [MQTT] Publish ACK for PID 717
[289511] [MQTT] Sending topic => CLOSED (PID 718)
[289519] [MQTT] Publish ACK for PID 718

This will work perfectly for my application.

The only issue I've found is if the rule were to be:

> rpnRule0 => "1 "00D7410E" rfb_match "topic" "CLOSED" mqtt_send"
> rpnRule1 => "1 "00D7410A" rfb_match "topic" "OPEN" mqtt_send"

You get the mqtt_send for each trigger (which makes sense). I'm not sure if the double receive of the code is an SRX882 module issue? As you have said, the idea of the rule is for it to be written to act on the "hits" to give the user the output they want.

[384423] [RF] Received code: 00D7410A
[384424] [RF] Action 0xA4
[384424] [RF] Received message 'C00101C61800D7410A'
[384424] [RF] Trying to match code D7410A
[384431] [MQTT] Sending SensorRF/rfin => C00101C61800D7410A (PID 837)
[384432] [RPN] new code: 00D7410A
[384439] [MQTT] Publish ACK for PID 837
[384453] [MQTT] Sending topic => OPEN (PID 838)
[384459] [MQTT] Publish ACK for PID 838
[385004] [RF] Received code: 00D7410A
[385004] [RF] Action 0xA4
[385005] [RF] Received message 'C00101C41800D7410A'
[385005] [RF] Trying to match code D7410A
[385012] [MQTT] Sending SensorRF/rfin => C00101C41800D7410A (PID 839)
[385013] [RPN] new code: 00D7410A
[385027] [MQTT] Publish ACK for PID 839
[385035] [MQTT] Sending topic => OPEN (PID 840)
[385042] [MQTT] Publish ACK for PID 840
[386638] [RF] Received code: 00D7410E
[386638] [RF] Action 0xA4
[386639] [RF] Received message 'C00101C21800D7410E'
[386639] [RF] Trying to match code D7410E
[386646] [MQTT] Sending SensorRF/rfin => C00101C21800D7410E (PID 841)
[386647] [RPN] new code: 00D7410E
[386665] [MQTT] Sending topic => CLOSED (PID 842)
[386684] [MQTT] Publish ACK for PID 841
[386735] [MQTT] Publish ACK for PID 842
[387224] [RF] Received code: 00D7410E
[387225] [RF] Action 0xA4
[387225] [RF] Received message 'C00101C21800D7410E'
[387225] [RF] Trying to match code D7410E
[387232] [MQTT] Sending SensorRF/rfin => C00101C21800D7410E (PID 843)
[387233] [RPN] new code: 00D7410E
[387238] [MQTT] Publish ACK for PID 843
[387256] [MQTT] Sending topic => CLOSED (PID 844)
[387263] [MQTT] Publish ACK for PID 844

@davebuk
Copy link
Contributor

davebuk commented Aug 3, 2020

For reference, I 'Learnt' the two codes for a dummy relay #0. The relay #0 operated and the rule fired correctly.

> rpnRule2 => "2 "00D7410E" rfb_match 0 1 relay"
> rpnRule3 => "2 "00D7410A" rfb_match 1 1 relay"

I then changed the rules to those above. This switched the dummy relay #1 as expected as well as operating relay #0.

[415092] [RF] Received code: 00D7410A
[415092] [RF] Action 0xA4
[415093] [RF] Received message 'C00101C21800D7410A'
[415093] [RF] Trying to match code D7410A
[415095] [RF] Match ON code for relay 0
[415099] [RF] Matched message 'C00101C21800D7410A'
[415103] [RELAY] #0 scheduled ON in 0 ms
[415108] [MQTT] Sending SensorRF/rfin => C00101C21800D7410A (PID 1004)
[415112] [RPN] new code: 00D7410A
[415119] [MQTT] Publish ACK for PID 1004
[415138] [RELAY] #0 set to ON
[415140] [MQTT] Sending SensorRF/relay/0 => 1 (PID 1005)
[415144] [MQTT] Publish ACK for PID 1005
[415673] [RF] Received code: 00D7410A
[415673] [RF] Action 0xA4
[415674] [RF] Received message 'C00101C21800D7410A'
[415674] [RF] Trying to match code D7410A
[415676] [RF] Match ON code for relay 0
[415680] [RF] Matched message 'C00101C21800D7410A'
[415685] [MQTT] Sending SensorRF/rfin => C00101C21800D7410A (PID 1006)
[415690] [RPN] refresh code=00D7410A hits=2 last=10415690
[415702] [MQTT] Publish ACK for PID 1006
[415711] [RELAY] #1 scheduled ON in 0 ms
[415712] [RELAY] #1 set to ON
[415714] [MQTT] Sending SensorRF/relay/1 => 1 (PID 1007)
[415719] [MQTT] Publish ACK for PID 1007
[416716] [RELAY] Setting relay mask: 0b11
[419722] [RF] Received code: 00D7410E
[419723] [RF] Action 0xA4
[419723] [RF] Received message 'C00101C31800D7410E'
[419724] [RF] Trying to match code D7410E
[419726] [RF] Match OFF code for relay 0
[419729] [RF] Matched message 'C00101C21800D7410E'
[419734] [RELAY] #0 scheduled OFF in 0 ms
[419738] [MQTT] Sending SensorRF/rfin => C00101C21800D7410E (PID 1008)
[419743] [RPN] new code: 00D7410E
[419752] [MQTT] Publish ACK for PID 1008
[419768] [RELAY] #0 set to OFF
[419771] [MQTT] Sending SensorRF/relay/0 => 0 (PID 1009)
[419784] [MQTT] Publish ACK for PID 1009
[420303] [RF] Received code: 00D7410E
[420304] [RF] Action 0xA4
[420304] [RF] Received message 'C00101C31800D7410E'
[420305] [RF] Trying to match code D7410E
[420307] [RF] Match OFF code for relay 0
[420310] [RF] Matched message 'C00101C21800D7410E'
[420316] [MQTT] Sending SensorRF/rfin => C00101C21800D7410E (PID 1010)
[420321] [RPN] refresh code=00D7410E hits=2 last=10420321
[420328] [MQTT] Publish ACK for PID 1010
[420349] [RELAY] #1 scheduled OFF in 0 ms
[420351] [RELAY] #1 set to OFF
[420353] [MQTT] Sending SensorRF/relay/1 => 0 (PID 1011)
[420360] [MQTT] Publish ACK for PID 1011
[421355] [RELAY] Setting relay mask: 0b0

@mcspr
Copy link
Collaborator Author

mcspr commented Aug 4, 2020

Based on the original issue, knowing 2nd code would've helped :) Togging on a single one still only possible with the rule string.

Also note that learn and having codes on the RF page already does relay switching by itself, so rule2 and rule3 are not really doing anything. Plus, because rules are just sequences of actions, rule0 cancels out rfb_match in rule2 (and rule1 cancels out rule3). Maybe it makes more sense for them not do that though, because only other option is to do everything in a single rule string.

@davebuk
Copy link
Contributor

davebuk commented Aug 4, 2020

The original issue was that if you had an RF transmitter sensor that only produce a single code for open and close, due to the code being seen twice, the learnt switch just toggles immediately. Like you said, the rfb_match solves that issue.

The switching of relay #1 via rules was just me testing how rules work generally. I disabled the original mqtt_send rules to test the relay switching rules as you said multiple rules wouldn't work based on the same trigger code seen by rfb_match.

@mcspr
Copy link
Collaborator Author

mcspr commented Aug 4, 2020

I meant

[420310] [RF] Matched message 'C00101C21800D7410E'

Which comes from the RF module. Rules fire simultaneously with that

edit: btw, any thoughts on terminology used? 'hits', 'match', etc.

- fix ifn to move stack instead of just moving values
- fix parser accidentally treating things as float
- fix parser empty space checks, treat newline as token separator
- fix math operators not properly propogating the error
- fix type capacity calculation for numerical conversions
- add inf and nan operators
- add u and i suffixes for dot-less numbers, makes expression push unsigned or int
- support escaped characters in strings

This also makes strings in-place, by appending a single character at a time,
*possibly* slowing them down.
@davebuk
Copy link
Contributor

davebuk commented Aug 8, 2020

Is there a standard terminology for multiple triggers? EVENTS maybe or COUNT?

@mcspr
Copy link
Collaborator Author

mcspr commented Aug 9, 2020

Count might work.

  • rpnlib bump, count number in expression can have u suffix to slightly reduce the parsing time (e.g. 123u "code" rfb_match)
  • codes with leading zeroes like 0000123456 become just 123456 (or, 000004 becomes 04, and etc.)
  • log operator renamed to dbgmsg to avoid collisions with logarithm operator (disabled by default though)
  • debug renamed to showstack
  • rfb.codes terminal command to show the current list of codes

@davebuk
Copy link
Contributor

davebuk commented Aug 16, 2020

Is there anything else you would like me to test while I have my development setup running? If not, I'll look to add the SRX into one of my 'in use' boards and run the RPN rules as is and update if needed when it's merged with the main Dev code.

@mcspr
Copy link
Collaborator Author

mcspr commented Aug 16, 2020

Nothing comes to mind so far, thanks!
Right now all that is left is minor refactoring, which will move things around but not really change the functional part.

@mcspr
Copy link
Collaborator Author

mcspr commented Aug 22, 2020

Hm. While looking at !rfb_direct vs. rfb_direct modes, I remembered that we actually have more than 1 protocol available.
(barring the case when user installs firmware from https://github.com/Portisch/RF-Bridge-EFM8BB1/, but that would imply user very carefully read the wiki footer and / or used Tasmota previously, where they integrate the flasher...)

I'll change the rfb_match & rfb_sequence to also have an additional arg that accepts unsigned index of the protocol (counting from 1!) as defined in the headers here -> https://github.com/sui77/rc-switch/blob/ebe91719936265540adcb9766f6ed6e09befe48f/RCSwitch.cpp#L82-L93

Debug log codes above use a single protocol - 2nd byte is always the same (C0>>>01<<<...).

@mcspr mcspr changed the title WIP: rfbridge rpn rules rpn: rfbridge rules Aug 26, 2020
@mcspr mcspr merged commit 1f9479b into xoseperez:dev Aug 26, 2020
@mcspr mcspr deleted the rpn/rfb-codes-plus branch August 26, 2020 22:21
@mcspr
Copy link
Collaborator Author

mcspr commented Aug 26, 2020

Smallish changes based on the #2335

  • As noted above, every code now needs proto before it, e.g. 5u 1u "AABBCC" rfb_match. Number can be taken from the serialized string, it's the 2nd byte
  • RC switch library version is the same as in OpenMqttGateway (2 commits earlier, to be precise).
  • Leading zeroes are no longer removed, this is handled by the new rc-switch integration in the rfbridge module which keeps them based on the 'bits' byte, just before the payload bytes
  • (related to the rfb: rework both efm8bb1 & rcswitch implementations #2335) if you happen to have any codes configured via the default relay integration, set cfg "4" and reboot will fix them. migration procedure will remove leading zeroes based on the 'bits' value, keeping as much bytes as it sees fit.
    This issue only happens on dev branch and needs manual intervention. 1.14.1 or older, migration is expected to happen automatically

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants