[SOLVED] Sonoff dual - Roller shutter

Hi, i’m using the sonoff dual (tasmota firmware | interlock mode on) to control my roller shutter .
I can set down, stop and up, but i couldn’t realize how to make an script that allows me to open and close x% of the roller shutter.
Could anyone help me?

This is how i do the up/down/stop thing.

rule "Persiana"
    Item PComedor_Action received command UP

rule "Persiana"
    Item PComedor_Action received command STOP

rule "Persiana"
    Item PComedor_Action received command DOWN

Thanks a lot,


You are going to struggle with that.
You would need to time exactly how long it takes to open the blind and then use a timer
Same for closing.
But in the long run it will go out of sync because you don’t have a sensor telling you when it’s opened fully or closed fully.

It’s best to use a dedicated blind controller. I am not the only one giving this advice. You will run into countless problems trying to do it this way.

In fact I did this for my shutters:
some items:

Switch mqttSonoff6_1 "SOnOff 6-1 [%s]" {mqtt=">[mosquitto:sonoff_t6/cmnd/POWER1:command:*:${command}],<[mosquitto:sonoff_t6/stat/POWER1:state:REGEX((.*))]"}
Switch mqttSonoff6_2 "SOnOff 6-2 [%s]" {mqtt=">[mosquitto:sonoff_t6/cmnd/POWER2:command:*:${command}],<[mosquitto:sonoff_t6/stat/POWER2:state:REGEX((.*))]"}
String mqttSonoff6lwt "SOnOff 6 [%s]" { mqtt="<[mosquitto:sonoff_t6/tele/LWT:state:default]" }
String mqttSonoff6state "SOnOff 6 [JSONPATH($.Wifi.RSSI):%s %%]" { mqtt="<[mosquitto:sonoff_t6/tele/STATE:state:default]" }
Rollershutter Sonoff6 "SOnOff 6 [%d%%]" { autoupdate="false" }

two rules:

var long intStartTime
var Timer tMqtt6 = null
var boolean lMqtt6 = false

rule "Sonoff6"
    Item mqttSonoff6_1 changed or
    Item mqttSonoff6_2 changed
    logDebug("sonoff","6: {} is {}",triggeringItem.name,triggeringItem.state)
    if(triggeringItem.state==ON) {
        logDebug("sonoff","6: StartTime= {}",intStartTime)
    else {
        val long myPercent = (now.millis - intStartTime)/140
        logDebug("sonoff","6: StopTime= {}; Duration= {}",now.millis, now.millis-intStartTime)
        logDebug("sonoff","6: Percent= {}",myPercent)
        if (!(Sonoff6.state instanceof Number)) Sonoff6.postUpdate(0)
        if (triggeringItem.name == "mqttSonoff6_1") {
            Sonoff6.postUpdate(if(((Sonoff6.state as Number)-myPercent) > 0 ) (Sonoff6.state as Number)-myPercent else 0)
        else {
            Sonoff6.postUpdate(if(((Sonoff6.state as Number)+myPercent) < 100 ) (Sonoff6.state as Number)+myPercent else 100)

rule "Sonnoff6 2"
    Item Sonoff6 received command
    logDebug("sonoff","6-2: received command: {}",receivedCommand)
    if(receivedCommand instanceof Number) {
        logDebug("sonoff","6-2: received command is Number")
        lMqtt6 = true
        if(tMqtt6 !== null) tMqtt6.cancel
        val Integer iDuration = (((receivedCommand as Number) - (Sonoff6.state as Number)) * if((receivedCommand as Number) > (Sonoff6.state as Number)) 140 else -140).intValue
        logDebug("sonoff","6-2: Duration: {} mSec",iDuration)
        if((receivedCommand as Number) < (Sonoff6.state as Number)) {
            logDebug("sonoff","6-2: UP!")
        else {
            logDebug("sonoff","6-2: DOWN!")
        tMqtt6 = createTimer(now.plusMillis(iDuration), [
            logDebug("sonoff","6-2: STOP!")
            if(mqttSonoff6_1.state == ON) mqttSonoff6_1.sendCommand(OFF)
            if(mqttSonoff6_2.state == ON) mqttSonoff6_2.sendCommand(OFF)
            tMqtt6 = null
            lMqtt6 = false
        ] )
    else if (!lMqtt6)
        switch (receivedCommand) {
            case UP: mqttSonoff6_1.sendCommand(ON)
            case DOWN:mqttSonoff6_2.sendCommand(ON)
            case STOP: {
                if(mqttSonoff6_1.state == ON) mqttSonoff6_1.sendCommand(OFF)
                if(mqttSonoff6_2.state == ON) mqttSonoff6_2.sendCommand(OFF)

in a sitemap:

Default item=Sonoff6
Selection item=Sonoff6 mappings=[ 0="0%",25="25%",50="50%",75="75%",100="100%" ]

But recently I found a fork from tasmota which does the calculation within tasmota! https://github.com/stefanbode/Sonoff-Tasmota I have not tested this yet, but it sounds promising :wink:


Udo, How do you know that when the percentage reaches 0% the blind is actually closed?
Or 100% and fully opened?

Sorry, didn’t mention this…

The Shutter needs 14 seconds to completely run up/down, so runtime in Milliseconds/140 is percentage (calculated in first rule)

It’s not exact, but exact enough :wink:

My point exactly. As long as you don’t have a sensor to confirm fully opened or closed, your system will eventually get out of sync.
It’s a good rule, though. I like it and I may try something like this for shutters in the shed. (I don’t want to spend more than a sonoff dual for that purpose)

Thanks a lot. It´s exactly that i´m looking for. I´m very happy!!!

Now i´m trying to make it work but…

2018-07-29 18:36:18.210 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Sonnoff6 2': Could not cast NULL to java.lang.Number; line 38, column 66, length 23

According to what I saw. The item is not initialized. How do I have to do?

Thank you so much,


Ah, yes, forgot to mention this… I have persisted the item (plus restoreOnStartup) and in an old version of the rule there was a part which took care of that…

Please add a line like this:

if (!(Sonoff6.state instanceof Number)) Sonoff6.postUpdate(0)

right after the logDebug() in the first rule.

I have added the line in my posting above…


Thanks a lot, i maked it work with that line, but i couldn’t use the open all, close all function. When i check the log, it’s says:

`2018-08-02 00:34:07.082 [WARN ] [.core.transform.TransformationHelper] - Cannot get service reference for transformation service of type REGEX

2018-08-02 00:34:07.085 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'mqttSonoff6_2'

2018-08-02 00:34:07.081 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Sonoff6': The name 'Sonoff6Dur' cannot be resolved to an item or type; line 17, column 9, length 10

2018-08-02 00:34:07.143 [WARN ] [.core.transform.TransformationHelper] - Cannot get service reference for transformation service of type REGEX

2018-08-02 00:34:07.147 [WARN ] [b.core.events.EventPublisherDelegate] - given new state is NULL, couldn't post update for 'mqttSonoff6_2'`

Thanks again!


Sorry, forgot to kill this line:


this part is not necessary to make the rules work, it was only to give additional information when creating the rules.

In question of the REGEX warning, I don’t use REGEX at all in this rules, so this issue can’t be mine :wink:

Same for the given new state is NULL, couldn't post update for 'mqttSonoff6_2', as I only used mqttSonoff6_2.sendCommand(ON|OFF), there is nothing which could send a NULL to mqttSonoff6_2 in my rules.

1 Like

Thanks a lot! You did it! One more question. How do you reset the rule so i can tell that the roller shutter is full open?



I don’t do this :slight_smile: I simply send the shutter to up (or down) position. (e.g. morning and evening)
The Sonoff will switch off after maximum runtime, and after that the upper or lower position should be reached. As the maximum runtime is used, the counter should go to 100% or 0%.

Thanks a lot for all your help! Now i´ll check the tasmota mod.


Yes, this is on my roadmap, too :slight_smile:

why go out of synck? and the cause?

…I take advantage of the post to thank Hudo Hartmann for his excellent work

I used your code with a shelly 2.5 and the tasmota firmware. Everything works perfectly, moreover the buttons connected to the shelly also allows me to have feedback in case of using the buttons near the window. The only problem is that if you press up and down together from OH the motor is powered in both directions, risking damage. How can I fix this? I’m not very good with the rules

Please set option 14 to 1 (this is relay interlock). When using the current version of Tasmota, the command is “Interlock 1”

thanks for the reply, I solved. Specific only, to help those who read the post, with the latest version of Tasmota ( the Option14 command has been replaced by “interlock” 0 (off) or 1 (on)

There is a technique to overcome this situation. (I used to see it used in connection with stepper-motor controlled valves, with no sensing.)
It relies on your mechanism being capable of being safely driven to a mechanical end stop, plus a bit more.
If it is going to bend or break something in that situation, Sod’s Law says that will happen anyway one day - so I’d imagine rollers would be safe for this “abuse”?!

Anyway, the point is;
Say you know your roller takes at most 15 secs for full travel.
If you drive it this way or that for 17 secs, you know (barring faults) that it must have got to the fully open/closed stop, regardless of where it started.
In my stepper-motor example, at system start it would always (over) drive the valve fully closed and zero the software step position counter.

In openHAB, you’d want to intercept any fully-open or fully-closed commands so that you could apply that overdrive, and then reset your calculated position.

You could invent a special calibration routine of course, but I’d imagine among your ordinary controlling rules there will be requirements for fully open/closed that can exploited for this purpose. Periodic self-calibration.

You don’t even need the “full 17 seconds” or whatever if you are reasonably confident the calibration doesn’t get too far adrift - just add a second or two to calculated travel time from “here” to “end”.

I studied the rule, with my basic notions, to be able to integrate google home. If I understand, by logDebug the rule assigns the percentage to the item Sonoff6 and calculates the activation time. While the second rule acts on the three cases UP DOWN and STOP.
I also can’t understand the meaning of 6-2 in

logDebug ("sonoff", "6-2: received command: {}", receivedCommand)

To integrate GH I had thought of creating two more items (without sitemaps) one for OPEN and one for CLOSE, this to tag them with [“Switchable”] and insert a third rule that set the item Sonoff6 equal to zero (opening) or to 100 (closure)

I made some attempts but with negative results, is it possible to get help?
thank you