How to set up a controlled garage door?

Hi, I am just making my first steps with openHAB, moving over from a self-written interface. My first appliance is a garage door that is not only monitored (Contact) but can also be controlled. I regularly do that “remotely”, e.g. when I am leaving the highway, or after I have already driven out of reach of common RF solutions

It is connected via MQTT:

  • The controlling is done in one topic, say garage/door/cmd, where it listens for open and close commands.
  • The monitoring is done in a second topic, say garage/door/status, where it publishes retained messages every time the status changes.
  • The status changes after quite a few seconds, since it only reports a new status when the door is actually almost there.

I do have openHAB with MQTT running, but I am unsure how to model this item. What comes to my mind is a switch, however, I have some problems with is:

  • Clicking always changes the status of the switch, regardless if the door status really changed or it was e.g. blocked. With the autoupdate=“false” option, this is solved, but my interface doesn’t seem to update on short notice, so it changes to the other extreme of being too static.
  • An external status change changes the switch, but it also fires a new switch event, issuing a new event in the cmd channel. The controller is written in a way that this SHOULD not be a problem, but still it is unelegant.
  • Cosmetics-wise: While there are icons for a garage door, they do not seem to work with switch, since the variants are “open”, “closed”, not “on”, “off”. Haven’t seen a translation in the docs yet, but that might be on me.

So, is there an elegant way to deal with this? What I am looking for is a control that shows the status, gives some feedback that my click was recognized and then changes state when an actual new state is received.

I have a very similar configuration.

I have a relay wired to the opener’s push button which toggles on and off upon receipt of a message on an MQTT topic. I have a reed switch that indicates the open/closed state of the garage door, again reported on a different MQTT topic.

The key in modeling this is to separate the actuator (i.e. the thing that causes the door to open/close) from the sensor (i.e. the thing that tells you whether the door is open or not) into separate Items. They really are two distinct things with distinct purposes so they really should be separated.

I have the relay represented in OH as a Switch Item but on the sitemap it is represented as a single button. Any command sent to this switch will generate a message to the relay topic and the controller simulates the button press on the opener (500 msec high, then back to low). I actually have yet another switch bound to the MQTT topics to send the actual messages because I have a bunch of stuff I want to do before the message gets sent in a rule.

I have the reed switch represented in OH as a separate Contact Item. In answer to your cosmetics question, it is documented in the Items wiki page. In short, the last part of the name of an Icon is how OH maps the state to the icon. So if you are using a Switch which can only be ON or OFF, it will only work with icons ending in on.png or off.png (e.g. light_on.png and light_off.png). Since the door icons end in open.png and closed.png they won’t work with a Switch (unless you make copies of them and rename to end in on.png and off.png).

When the door is opened externally to OH, only the reed switch triggers a message to OH and because the actuators and sensors are separate Items there is no looping problem.

On the sitemap I use the state of the Contact Item to turn on/off visibility of the switch based on the state of the contact so I can simulate the changing of the Open/Closed door icons and change the word on the button. NOTE: this trick doesn’t always work that well, particularly on the phones due to a problem with refreshes in OH 1.

My code (notes: I have two openers and I treat the garage door sensors just like all my other door sensors and I’ve posted my rules here as they exist in my file with some additional comments so there will be a bunch of extra stuff in the rules, let me know if you have questions. I also didn’t include all the groups as they are outside the scope of this conversation):

#Items

// Items to represent the door openers on the sitemap and receive commands
Switch  T_D_Garage1 "Garage Door 1" <garagedoor> (gHistory, gMyOpenhab, gGarageOpeners)
Switch  T_D_Garage2 "Garage Door 2" <garagedoor> (gHistory, gMyOpenhab, gGarageOpeners)

// Items to send the trigger command to the openers
Switch  T_D_Garage1_MQTT "Garage Door 1" { mqtt=">[mosquitto:actuators/garage1:command:*:default]"}
Switch  T_D_Garage2_MQTT "Garage Door 2" { mqtt=">[mosquitto:actuators/garage2:command:*:default]"}

// Items to represent the open/closed status of the opener
Contact N_D_GarageDoor1  "Garage Door 1 [MAP(en.map):%s]" <garagedoor> (gHistory, gDoorSensors, gRemindDoorSensors, gCerberosSensors) { mqtt="<[mosquitto:entry_sensors/main/garage/door1:state:default]" }
Contact N_D_GarageDoor2  "Garage Door 2 [MAP(en.map):%s]" <garagedoor> (gHistory, gDoorSensors, gRemindDoorSensors, gCerberosSensors) { mqtt="<[mosquitto:entry_sensors/main/garage/door2:state:default]" }

// Item to represent the online status of the garage controller (uses MQTT LWT messages as well as NH binding)
// The corresponding rules for these Items are not included
Switch N_C_Cerberos_mqttReporter "Cerberos MQTT Reporting Service [%s]" <network> (gRemoteSensors, gCerberosNet) { mqtt="<[mosquitto:status/sensor-reporters:command:OFF:.*cerberos sensorReporter is dead.*]" }
Switch  N_C_CerberosRaspi             "Cerberos Server"    <network>    (gCerberosNet) { nh="192.168.1.203" }

Garage Door Opening Rules

import org.openhab.core.library.types.*
import org.openhab.core.library.items.*
import org.openhab.model.script.actions.*
import org.joda.time.*
import org.eclipse.xtext.xbase.lib.*

val Functions$Function1 openGarage = [ String garageNum |

        logInfo("Garage Controller", "The Garage Door " + garageNum + " opener has been triggered")

        // Send the command to the opener's MQTT Topic
        switch garageNum {
                case "1" : T_D_Garage1_MQTT.sendCommand(ON)
                case "2" : T_D_Garage2_MQTT.sendCommand(ON)
                default : logError("Garage Controller", garageNum + " is an unknown garage!")
        }

        // Alert if the opener controller is down
        if(N_C_Cerberos_mqttReporter.state != ON) {
                Notification_Proxy_Alarm.postUpdate("The garage controller may be offline, trigger may have failed!")
        }

        // Alert if the opener was triggered and no one is home.
        if(Present.state != ON) {
                Notification_Proxy_Alarm.postUpdate("Garage door " + garageNum + " has been triggered and no one is home!")
        }
]

rule "Trigger Garage Door Opener 1"
when
        Item T_D_Garage1 received command or
        Item T_C_Minimote_1_Button1_Short changed to ON or
        Item T_C_Minimote_1_Button1_Long changed to ON or
        Item T_C_Minimote_2_Button1_Short changed to ON or
        Item T_C_Minimote_2_Button1_Long changed to ON
then
        openGarage.apply("1")
end

rule "Trigger Garage Door Opener 2"
when
        Item T_D_Garage2 received command or
        Item T_C_Minimote_1_Button2_Short changed to ON or
        Item T_C_Minimote_1_Button2_Long changed to ON or
        Item T_C_Minimote_2_Button2_Short changed to ON or
        Item T_C_Minimote_2_Button2_Long changed to ON
then
        openGarage.apply("2")
end

Garage Door Open Status Rules

import org.openhab.core.library.types.*
import java.util.Formatter
import java.util.Locale
import org.joda.time.*
import org.joda.time.format.*
import java.util.Map
import org.openhab.model.script.actions.*

// Lets me keep track of sent notifications so we don't send more than one per event
val Map<String,Boolean> openNotif = newHashMap

// The entry sensors will report the current status when it receives "update" on the update MQTT topic
rule "Get update at startup"
when
        System started or
        Item T_Update received command // used for debugging
then
        logInfo("Alarm Controller", "Requesting an update from the MQTT sensors")
        N_D_Update.postUpdate("update")
end

// A reed switch changed state
rule "A Door's State Changed"
when
        Item N_D_Front changed or
        Item N_D_Back changed or
        Item N_D_Garage changed or
        Item N_D_GarageDoor1 changed or
        Item N_D_GarageDoor2 changed
then
        // get the doors that changed in the last second
        gDoorSensors.members.filter(door|door.changedSince(now.minusSeconds(1))).forEach[ door |

            val StringBuilder msg = new StringBuilder
            msg.append("The ")
            var String name = door.name.split("_").get(2)
            if(name.contains("Door")){
                msg.append("Garage Door ")
                msg.append(name.substring(name.length - 1))
            }
            else{
                msg.append(name)
                msg.append(" Door")
            }
            msg.append(if(door.state == OPEN) " was opened" else " was closed")
            var alarm = false

            // Generate alarm message if needed
            if(Present.state != ON) {
                msg.append(" and no one is home")
                alarm = true
            }

            if(TimeOfDay.state.toString == "Night") {
                msg.append(" and its night")
                alarm = true
            }

            msg.append("!")

            // Save the date/time for openings
            if(door.state == OPEN) {
                gDoorSensorsTime.members.filter(dt|dt.name == door.name+"_Last_Opened").head.postUpdate(new DateTimeType().toString)
            }

            // Note the opening and send alert
            logInfo("Entry", msg.toString)
            if(alarm) {
                // Wait 30 seconds and check again before sending an alert if we are not home
                if(msg.toString.contains("no one") && !msg.toString.contains("night")) {
                        try {Thread::sleep(30000)} catch(InterruptedException e){}
                        if(Present.state != ON) Notification_Proxy_Alarm.sendCommand(msg.toString)
                }
                // At night send the alarm immediately
                else {
                    Notification_Proxy_Alarm.sendCommand(msg.toString)
                }
            }

            // Reset the notification flag
            openNotif.put(door.name, false)
        ]
end

rule "Reminder for doors that are open for over hour that we want to know any time"
when
        Time cron "0 0/15 * * * ?"
then
        gRemindDoorSensors.members.filter[s|s.state == OPEN && !s.changedSince(now.minusHours(1))]?.forEach[ door |
                if(!openNotif.get(door.name)){
                        val String msg = door.name + " is still open after an hour!"
                        Notification_Proxy_Alarm.postUpdate(msg)
                        openNotif.put(door.name, true)
                }
        ]
end

rule "Reminder for doors that are open for over an hour at night"
when
        Time cron "0 0/15 * * * ?"
then
        if(TimeOfDay.state.toString == "Night") {
                gDoorSensors.members.filter[s|s.state == OPEN && !s.changedSince(now.minusHours(1))]?.forEach[ door |
                        if(!openNotif.get(door.name)){
                                val String msg = door.name + " is still open and its night!"
                                Notification_Proxy_Alarm.postUpdate(msg)
                                openNotif.put(door.name, true)
                        }

                ]
        }
end

rule "Warning about doors when we leave the house"
when
        //Item Present received command OFF
        Item gRichPresent changed to OFF or
        Item gJennPresent changed to OFF
then
    // We don't want to wait the five minutes for Present to change
        if(gRichPresent.members.filter[r|r.state == ON].size == 0 &&
           gJennPresent.members.filter[j|j.state == ON].size == 0) {

                gDoorSensors.members.filter(s|s.state == OPEN).forEach[door |
                        Notification_Proxy_Alarm.postUpdate("You left " + door.name + " open!")
                        openNotif.put(door.name, true)
                ]

        }

end

#Sitemap

                // Garage Door Openers
                Switch item=T_D_Garage1 label="Garage Door 1" icon="garagedoor-closed" mappings=[ON=Open] visibility=[N_D_GarageDoor1!="OPEN"]
                Switch item=T_D_Garage1 label="Garage Door 1" icon="garagedoor-open" mappings=[ON=Close] visibility=[N_D_GarageDoor1=="OPEN"]
                Switch item=T_D_Garage2 label="Garage Door 2" icon="garagedoor-closed" mappings=[ON=Open] visibility=[N_D_GarageDoor2!="OPEN"]
                Switch item=T_D_Garage2 label="Garage Door 2" icon="garagedoor-open" mappings=[ON=Close] visibility=[N_D_GarageDoor2=="OPEN"]
1 Like

Hi, thanks, that helps a lot!

Also have a look at the examples for the Garadget binding. It uses a Rollershutter item that publishes commands and listens to state in the one item. A very similar binding config can be done with the MQTT binding. One addition is using autoupdate="false" so the state of the item is only updated by MQTT, not by you sending commands (the Garadget binding suppresses updates on bound items instead of requiring autoupdate="false"). Like:

Rollershutter doorState "Garage Door" <rollershutter> { mqtt=">[broker:/garage/door/cmd:command:*:default],<[broker:/garage/door/status:state:default]",autoupdate="false" }

Ok, I tested this and after solving a few misunderstandings, I think this should be sufficient. I just have one problem: The icon sometimes resets to “rollershutter.png” instead of -0/-100. When I use the control, it is updated fine (now it is also responsive, don’t know what was the problem before) but sometimes, without being able to reproduce it, it resets to the stateless icon. I’ll keep an eye on that.

Thanks for all the help!

OK I think I have an acceptable version of this. Tell me if I don’t. I have an Arduino with two reed switches (Open and Closed) that report on one MQTT topic (garage/door). I want to know if the door is open, closed, or otherwise. I’m even going to report the otherwise as opening or closing. As you can see, I use String instead of Contact to pull this off. Any downfall there? My one big issue is that the icon for the switch doesn’t change from the half open icon, even though the button text does. It changes fine for the status.

.items

String	GDoor			"Door is [MAP(door.map):%s]" <garagedoor>	(gGarage)	{ mqtt="<[mosquitto:garage/door:state:default]" }
Switch	GDoorButton		"Garage door"								(gGarage)	{ mqtt=">[mosquitto:garage/openclose:command:*:default]" }

.sitemap

Text item=GDoor
Switch item=GDoorButton label="Garage Door" icon="garagedoor-closed" mappings=[ON=Open] visibility=[GDoor=="CLOSED"]
Switch item=GDoorButton label="Garage Door" icon="garagedoor" mappings=[ON=Reverse] visibility=[GDoor=="OPENING",GDoor=="CLOSING"]
Switch item=GDoorButton label="Garage Door" icon="garagedoor-open" mappings=[ON=Close] visibility=[GDoor=="OPEN"]

.map

OPEN=Open
CLOSED=Closed
CLOSING=Closing...
OPENING=Opening...
NULL=unknown

In OH 2 you must name the icons to match what the state is mapped to in your label. Unfortunately that means you probably cannot use “Closing…” with the three dots.

The GDoor status item’s icon works (by defining the icon in .items). The GDoorButton icon does not change with the visibility and explicit icon call (icon=“garagedoor-closed”) in .sitemap. Even though the mappings=[ON=Open] does.

Also, after a publish on the topic, iOS updates right away but the browser one does not (it was for a while but isn’t now…).

IE   Basic UI         Auto updates         Switch Icon does NOT change
IE   Classic UI      Auto updates         Switch Icon DOES change
FF  Basic UI        No auto update       Switch Icon does NOT change
FF  Classic UI      Auto updates         Switch Icon does NOT change
iOS                     Auto updates         Switch Icon does NOT change

I’ve also found that is also a difference with OH 2. I’ve seen the same behavior and simply have not looked into it enough to figure out if it is a difference or something I’m doing wrong.

I’ve worked around the problem by making two new copies of the opened and closed icons that are not dynamic and used those instead.

Switch item=T_D_Garage1 label="Garage Door 1" icon="gdc" mappings=[ON=Open] visibility=[N_D_GarageDoor1!="OPEN"]
Switch item=T_D_Garage1 label="Garage Door 1" icon="gdo" mappings=[ON=Close] visibility=[N_D_GarageDoor1=="OPEN"]

If you are on Beta 4 then this is a known bug that has been fixed.

Yeah, I thought about that. I’m usually not a patient person but with a beta product and a feature that SHOULD work, I’m usually willing to wait for it to work without a workaround. Does this need reported?

I am. Awesome! If I wanted that fix, how would I get it? Nightly snapshot?

Do you see any problem with using String instead of Contact?

Working differently does not necessarily mean it is working incorrectly. But an issue reported I’m sure would either be addressed or closed because this is the way it is supposed to work now.

Assuming apt-get, see the Snapshot section of the following link for how to grab the nightly build via apt-get.

http://docs.openhab.org/installation/linux.html#package-repository-installation

If manual install you can download the nightly built distro zip from here:

https://openhab.ci.cloudbees.com/job/openHAB-Distribution/

It all depends on what you want to do with it. With Contact you have two nice and well defined states that it can be making error checking and writing rules triggers easier in some cases. With String you can have more than just two states.

True. So the sitemap SHOULD NOT display the explicitly defined icons? :confused: The only difference in your workaround is that they aren’t the built in ones. Why would that be the expected behavior?

Read: “Be careful and pay attention in rules/scripts.” Got it.

They have clearly changed how dynamic icons work in OH 2. For example, in Basic UI they now support gradual icons like a battery meter for Number Items.

As part of this change is now a new requirement that there must be a default version of an icon (i.e. one that does not include the “-state” part of the icon).

It is perfectly reasonable that these changes result in a sitemap from no longer being able to explicitly use the icon for a specific state.

My work around is to make a copy of the icons without the state part of the name.

This behavior could be by design, it could be an unfortunate limitation imposed to support the battery meter like icons, or it may be a regression that no one thought to test for.

I was in OH 1.x for about a week and never got this far. But much of the documentation still refers to 1.x stuff that may or may not be in 2 or at least the same in 2. (OK, or at least that documentation is easier to come across. I’d really like to help with documentation but I’ve got to get the supporting systems up and running on W10.)

I can’t imagine that this wouldn’t be supported (although I CAN see how it would be low on the list). I mean, if you can show the state of the object AND control it, all within one sitemap line, why wouldn’t you? “The door is closed, do you want to open it?” I would bet that it’s a regression, only because it works like a charm in IE with the Basic UI. But I could be wrong and so I wouldn’t bet more than a Starbucks.

Thanks for all the help (and inspiration) with this! Now I’ve got to concentrate on the Arduino side of things (ESP8266 Wifi, CC3000 was a bust).

1 Like

Hi

I know this is an old thread but it somehow fits to my topic.

I have a garage door which works with two switches (KNX) . One for open, one for close.
Then I have two reed sensors, one for fully open, one for fully close.

Is it possible, to have a switch in habpanel, which only shows the actual possible direction:
Reed Closed = 1 --> switch is Red and label is open {knx=5/1/1}
Reed Open = 1 --> switch is Green and label is close {knx=5/1/2}

If that is not possible, how can I show the status for the door. The usual contact item is not the right thing becaus i have three possible stati,
OPEN, CLOSE, something between.
With the usual contact item I can only handle one reed sennsor, but not CLOSE doesn´t mean fully open.

I hope some of you guys can help me with that issue.

THX

Yes
You need to create another item

String GarageDoorStatus
Rule "Garage door direction"
when
    ReedClosed changed to OPEN or //Door opening
    ReedOpen changed to OPEN //Door closing
then
    var doorStatus = ""
    if (triggeringItem.name.toString = "ReedClosed") doorStatus = "OPENING"
    if (triggeringItem.name.toString = "ReedOPEN") doorStatus = "CLOSING"
end

Rule "Garage door direction"
when
    ReedClosed changed to CLOSED or //Door closed
    ReedOpen changed to CLOSED //Door open
then
    var doorStatus = ""
    if (triggeringItem.name.toString = "ReedClosed") doorStatus = "CLOSED"
    if (triggeringItem.name.toString = "ReedOPEN") doorStatus = "OPEN"
end

Hello Vincent

Thx for your reply and help. I tried it today but got a lot of errors.
I creadet one new String Item “Status_Garagentor” and copied your rule. Now this looks like this

rule "Garage door direction"
when
    Status_Garagentor_close changed to OPEN or //Door opening
    Status_Garagentor_open changed to OPEN //Door closing
then
    var Status_Garagentor = ""
    if (triggeringItem.name.toString = "Status_Garagentor_close") Status_Garagentor = "OPENING"
    if (triggeringItem.name.toString = "Status_Garagentor_open") Status_Garagentor = "CLOSING"
end

rule "Garage door direction"
when
    Status_Garagentor_close changed to CLOSED or //Door closed
    Status_Garagentor_open changed to CLOSED //Door open
then
    var Status_Garagentor = ""
    if (triggeringItem.name.toString = "Status_Garagentor_close") Status_Garagentor = "CLOSED"
    if (triggeringItem.name.toString = "Status_Garagentor_open") Status_Garagentor = "OPEN"
end

I don´t know what I missed.
THX

You can’t use an item name as a variable
The comparison for equal is == not =

rule "Garage door direction"
when
    Status_Garagentor_close changed to OPEN or //Door opening
    Status_Garagentor_open changed to OPEN //Door closing
then
    if (triggeringItem.name.toString == "Status_Garagentor_close") Status_Garagentor.postUpdate("OPENING")
    if (triggeringItem.name.toString == "Status_Garagentor_open") Status_Garagentor.postUpdate("CLOSING")
end

rule "Garage door direction"
when
    Status_Garagentor_close changed to CLOSED or //Door closed
    Status_Garagentor_open changed to CLOSED //Door open
then
    if (triggeringItem.name.toString == "Status_Garagentor_close") Status_Garagentor.postUpdate("CLOSED")
    if (triggeringItem.name.toString == "Status_Garagentor_open") Status_Garagentor.postUpdate("OPEN")
end

Thank you for your fast respond.

I copied the code but got the following errors:
no viable alternative at input ‘Status_Garagentor_close’
no viable alternative at input ‘Status_Garagentor_open’
no viable alternative at input ‘Status_Garagentor_close’
no viable alternative at input ‘Status_Garagentor_open’
The method or field triggeringItem is undefined



Maybe you can give me another hint.

THX
Daniel