OpenBK7231T_App icon indicating copy to clipboard operation
OpenBK7231T_App copied to clipboard

Inability to do proper mutexing seems to be able to kill relays in some setups

Open C0rn3j opened this issue 4 months ago • 8 comments
trafficstars

I have electric roller blinds that share live and have a two input wires for connecting live to them to either go up and down.

They should not be able to trigger both states at the same time.

OBK only seems to allow to turn another input off after the current one already went on, resulting in a short time where both inputs are on - this seems to have fried two 10A230V relays of mine so far.

I would like the ability to do a proper mutex on two channels, ideally with a delay between the two.

Some more context in https://www.elektroda.com/rtvforum/viewtopic.php?p=21587087#21587087 and in https://github.com/openshwprojects/OpenBK7231T_App/issues/703#issuecomment-2980716857

Workaround for the time being would be welcome, I did not manage to come up with any.

C0rn3j avatar Jun 29 '25 19:06 C0rn3j

I can add some kind of mechanism, but how should it handle setChannel on mutexed channel? Should it delay setting new value? Or just skip set?

openshwprojects avatar Jun 30 '25 19:06 openshwprojects

Let's say channel 1 and 2 are mutexed and you do: backlog setChannel 1 1; setChannel 2 1; setChannel 2 1; setChannel 2 0; What should happen internally?

openshwprojects avatar Jun 30 '25 19:06 openshwprojects

In my case, it definitely should not skip.

Imagine user presses blinds down, but it won't do anything, because they already pressed blinds up accidentally x seconds earlier (the blinds take half a minute to move completely).

So I would expect

# 1. Channel 1 ON
setChannel 1 1; 
# 2. Channel 1 OFF, delay 100ms, Channel 2 ON
setChannel 2 1; 
# 3. Nothing, channel 2 is already on
setChannel 2 1; 
# 4. Channel 2 OFF
setChannel 2 0;

C0rn3j avatar Jun 30 '25 21:06 C0rn3j

Well, currently I can propose alternate solution. I have no solid ideas how to do what you said efficiently. We would need to queue set commands...

My alternate solution would be a driver that uses single channel to control two GPIOs. Value 0 is both down, value 1 is first high, value 2 is second high;

Here's my alternate solution self test. It should give you a basic idea how it will work. Do you think this can help for your scenario?: ` CMD_ExecuteCommand("startDriver PinMutex", 0); // setMutex <delayMs> <pinDown> <pinUp> CMD_ExecuteCommand("setMutex 0 0 100 10 11", 0);

SELFTEST_ASSERT(SIM_GetSimulatedPinValue(10) == 0);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(11) == 0);
Sim_RunMiliseconds(100, false);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(10) == 0);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(11) == 0);
CMD_ExecuteCommand("setChannel 0 1", 0);
// from 0 0 to 1 0 set is quick
Sim_RunMiliseconds(25, false);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(10) == 1);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(11) == 0);
CMD_ExecuteCommand("setChannel 0 2", 0);
Sim_RunMiliseconds(25, false);
// dead time
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(10) == 0);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(11) == 0);
Sim_RunMiliseconds(25, false);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(10) == 0);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(11) == 0);
Sim_RunMiliseconds(25, false);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(10) == 0);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(11) == 0);
Sim_RunMiliseconds(50, false);
// set
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(10) == 0);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(11) == 1);
CMD_ExecuteCommand("setChannel 0 1", 0);
Sim_RunMiliseconds(25, false);
// dead time
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(10) == 0);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(11) == 0);
Sim_RunMiliseconds(25, false);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(10) == 0);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(11) == 0);
Sim_RunMiliseconds(25, false);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(10) == 0);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(11) == 0);
Sim_RunMiliseconds(50, false);
// set
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(10) == 1);
SELFTEST_ASSERT(SIM_GetSimulatedPinValue(11) == 0);`

openshwprojects avatar Jun 30 '25 21:06 openshwprojects

preview sample: https://github.com/openshwprojects/OpenBK7231T_App/pull/1704 tested only in self test

openshwprojects avatar Jun 30 '25 21:06 openshwprojects

Are you able to convert your script logic to use the proposed approach? A single channel with 3 states - 0 "do nothing", 1 "move down", and "2 move up" ?

openshwprojects avatar Jun 30 '25 21:06 openshwprojects

I will try flashing the artifact on my second board tomorrow, but how would I make this tri-state switch show up as "up" and "down" in home assistant?

C0rn3j avatar Jun 30 '25 22:06 C0rn3j

i can add tristate channel type tomorrow, but for now, hm, a configuration.yaml custom entry?

openshwprojects avatar Jun 30 '25 22:06 openshwprojects

I OTA'd from I believe .118 (had to do it twice for it to register from the web ui for some reason) to OpenBK7231N_pinmutex_e0b0bf44041f.rbl and I think I am doing the correct thing here but it won't work:

Image

C0rn3j avatar Jul 01 '25 10:07 C0rn3j

ah it was not enabled on beken, i pushned new commit

openshwprojects avatar Jul 01 '25 17:07 openshwprojects

Looks like the documentation does not match the actual code, UP ends up being ms?

# OK
startDriver PinMutex

# Example in the code:
#// setMutex MutexIndex ChannelIndex PinUp PinDown DelayMs
# setMutex 0 1 10 11 50

# Bind first roller up/down
setMutex 0 1 1 2 500
> Error:GEN:PinMutex[0] = ch=1, up=500, down=2, t=1ms

# Bind second roller up/down
#setMutex 1 3 3 4 500

Later attempt here, ignore:

startDriver PinMutex
#setMutex MutexIndex ChannelIndex DelayMs PinDown PinUp
# Bind first roller up/down
setMutex 0 1 500 2 1
> Error:GEN:PinMutex[0] = ch=1, up=2, down=1, t=500ms
# Bind second roller up/down
#setMutex 1 3 500 4 3

C0rn3j avatar Jul 01 '25 18:07 C0rn3j

ah yes, i moved pins to end, because i realized that the same approach could be used for N-pin mutexes

openshwprojects avatar Jul 01 '25 18:07 openshwprojects

Okay I am failing here, mostly due to lack of understanding of channels/indexes.

setMutex 0 1 500 2 1
> Error:GEN:PinMutex[0] = ch=1, up=1, down=2, t=500ms

I don't get how to supply one channel when I am currently using two.

This is my current setup:

UP_1(1) / DOWN_1(2) / UP_2(3) / DOWN_2(4) Image

Image

What am I doing wrong?

C0rn3j avatar Jul 01 '25 18:07 C0rn3j

The ChannelIndex is a channel, PinDown/PinUp are PINS, like P9, etc, not channels. You dont need to set anything for them in www panel. #setMutex MutexIndex ChannelIndex DelayMs PinDown PinUp setMutex 0 0 500 9 10 setMutex 1 1 500 11 12

openshwprojects avatar Jul 01 '25 20:07 openshwprojects

I don't need to, or shouldn't?

Should I unset the configuration for the buttons(8,9,10,11), the relays(24,6,26,14), or both?

Your example with 9,10,11,12 matches the buttons but somehow off-by one on purpose or were the pin numbers a random example?

Without unsetting anything I still get the GEN err:

setMutex 0 0 500 6 24
> Error:GEN:PinMutex[0] = ch=0, up=24, down=6, t=500ms

setMutex 0 0 500 9 10
>Error:GEN:PinMutex[0] = ch=0, up=10, down=9, t=500ms

C0rn3j avatar Jul 01 '25 21:07 C0rn3j

I used random pin indexes. This gen err is just a log message for quick testing.

I think you should not have set pins in html page. That can interfere with driver.

openshwprojects avatar Jul 02 '25 06:07 openshwprojects

Hmm, but if I don't set the pins for Rel and run this:

startDriver PinMutex
setMutex 0 0 500 6 24
setMutex 1 1 500 14 26

I don't have a way to control things anymore

Image

If I do set them back, switching them to ON makes the relays turn on then immediately turn off, setting to OFF has no effect.

C0rn3j avatar Jul 02 '25 07:07 C0rn3j

ahh, i see, obk automatically detects relays, if no relays are found, then no buttons are shown. if that's the case, you need to go to web app and manually set channel type for your channels to, idk, for now maybe to Toggle or to LowMidHigh as a placeholder, I need to add a channel type for you

openshwprojects avatar Jul 02 '25 08:07 openshwprojects

So so far I have this:

startDriver PinMutex
setMutex 0 0 500 6 24
setMutex 1 1 500 14 26

// This aliased command will turn off relay on Channel after 10 seconds
// addRepeatingEvent	[IntervalSeconds][RepeatsOr-1][CommandToRun]
alias turn_off_after_time_1 addRepeatingEvent 35 1 setChannel 0 0
alias turn_off_after_time_2 addRepeatingEvent 30 1 setChannel 0 0
alias turn_off_after_time_3 addRepeatingEvent 35 1 setChannel 1 0
alias turn_off_after_time_4 addRepeatingEvent 30 1 setChannel 1 0

// this will run the turn off command every time that Channel becomes 1 or 2
addChangeHandler Channel0 == 1 backlog turn_off_after_time_1
addChangeHandler Channel0 == 2 backlog turn_off_after_time_2
addChangeHandler Channel1 == 1 backlog turn_off_after_time_3
addChangeHandler Channel1 == 2 backlog turn_off_after_time_4

I have a couple issues with this setup (which otherwise now seems to work fine with the new driver):


  1. I don't understand what this extra button column that's missing in the web app is:

Image

Image

  1. I am not able to make the physical buttons work properly, I do not see how I can now make them toggle the separate UP/DOWN states.

  2. The turn_off_after_time aliases do not die if the channel is set to 0, so if I toggle up, then down, there will be two timers running to turn the channel off at pretty much random times.

C0rn3j avatar Jul 02 '25 09:07 C0rn3j

hmm

Image

for buttons, you could just use Btn_SCriptOnly and just script click event to do setChannel 1 2 or setChannel 1 1 or setChannel 1 0

openshwprojects avatar Jul 02 '25 09:07 openshwprojects

"Remember that some pin roles require second channel field, which is only available on native interface right now."

Right, that extra field business is on me, my bad.

Now I only have the issue with the turn_off aliases not dying if the state is changed more than once, which is not that bad.

I have ended up with this so far:

startDriver PinMutex
setMutex 0 0 500 6 24
setMutex 1 1 500 14 26

// This aliased command will turn off relay on Channel after 10 seconds
// addRepeatingEvent  [IntervalSeconds][RepeatsOr-1][CommandToRun]
alias turn_off_after_time_1 addRepeatingEvent 40 1 setChannel 0 0
alias turn_off_after_time_2 addRepeatingEvent 30 1 setChannel 0 0
alias turn_off_after_time_3 addRepeatingEvent 40 1 setChannel 1 0
alias turn_off_after_time_4 addRepeatingEvent 30 1 setChannel 1 0

// This will run the turn off command every time that Channel becomes 1 or 2
addChangeHandler Channel0 == 1 backlog turn_off_after_time_1
addChangeHandler Channel0 == 2 backlog turn_off_after_time_2
addChangeHandler Channel1 == 1 backlog turn_off_after_time_3
addChangeHandler Channel1 == 2 backlog turn_off_after_time_4

// Aliases to be able to toggle between on/off state with physical buttons
alias click_up_1 if $CH0!=2 then "setChannel 0 2" else "setChannel 0 0"
alias click_down_1 if $CH0!=1 then "setChannel 0 1" else "setChannel 0 0"
alias click_up_2 if $CH1!=2 then "setChannel 1 2" else "setChannel 1 0"
alias click_down_2 if $CH1!=1 then "setChannel 1 1" else "setChannel 1 0"

addEventHandler OnClick 8 click_up_1
addEventHandler OnClick 9 click_down_1
addEventHandler OnClick 10 click_up_2
addEventHandler OnClick 11 click_down_2

Image

{
  "vendor": "Tuya",
  "bDetailed": "0",
  "name": "Full Device Name Here",
  "model": "enter short model name here",
  "chip": "BK7231N",
  "board": "TODO",
  "flags": "1024",
  "keywords": [
    "TODO",
    "TODO",
    "TODO"
  ],
  "pins": {
    "7": "Btn_Tgl_All;0;0",
    "8": "Btn_ScriptOnly;0;1",
    "9": "Btn_ScriptOnly;0;2",
    "10": "Btn_ScriptOnly;1;1",
    "11": "Btn_ScriptOnly;1;2",
    "22": "WifiLED_n;0"
  },
  "command": "",
  "image": "https://obrazki.elektroda.pl/YOUR_IMAGE.jpg",
  "wiki": "https://www.elektroda.com/rtvforum/topic_YOUR_TOPIC.html"
}

Looking forward to have this in officially, I'll try setting it up for real, fingers crossed no more relays eat it and this was truly the issue.

C0rn3j avatar Jul 02 '25 10:07 C0rn3j

we can have it officialy, or just do a better shutter driver as a next step if you have time, would you be able to post later a summary and guide of our work to elektroda?

the most basic solution to "not canceling" is to use addRepeatingEventID and then cancelRepeatingEvent, or, should i say, first cancelRepeatingEvent and then add fresh event

maybe i could even do one step more and add addRepeatingEventUID (unique id) that automatically cancels previous instance?

openshwprojects avatar Jul 02 '25 13:07 openshwprojects

channel type... Image

openshwprojects avatar Jul 02 '25 13:07 openshwprojects

we can have it officialy, or just do a better shutter driver as a next step if you have time, would you be able to post later a summary and guide of our work to elektroda?

I don't mind, I'd be mostly copypasting from my last post here anyways.

Though I suppose I'll wait til this is merged into the main build, as to not to have to rewrite it later.

maybe i could even do one step more and add addRepeatingEventUID (unique id) that automatically cancels previous instance?

That sounds neat and simpler for the user to script

C0rn3j avatar Jul 02 '25 14:07 C0rn3j

added addRepeatingEventUID , not tested yet

openshwprojects avatar Jul 02 '25 14:07 openshwprojects

hey , any feedback, news?

openshwprojects avatar Jul 06 '25 09:07 openshwprojects

I have not tried the repeating events, but I have been running the custom build (pinmutex_9c30a7621d99) without a hitch, so far the relays have survived, so I suppose lack of mutexing was indeed my root issue.

EDIT: I did the writeup, kept it small with keeping the scripting and config portions in one place - here on GH.

C0rn3j avatar Jul 06 '25 19:07 C0rn3j

Anything I can do to help get this in master?

C0rn3j avatar Aug 05 '25 20:08 C0rn3j

This can be easily merged, but probably not enabled by default due to flash size limitations

openshwprojects avatar Aug 10 '25 10:08 openshwprojects

Does this mean it'd get a separate build, for example like IrRemoteESP does?

C0rn3j avatar Aug 12 '25 21:08 C0rn3j