Goodby MyQ, say hello to ratgdo Garage Door control

Well, it’s time to ban MyQ from my home (wasn’t working now for years), and say hello to ratgdo (Rage Against the Garage Door Opener).
A big shout-out and thank you to Paul Wieland who is the creator behind ratgdo!!

For anybody planning to do use ratgdo, here is my journey and I hope it will help you to bring your garage door back into your openHAB setup.
I am still running openHAB 2.5.12, since everything I need works and why change a running system…
I do use configuration files for all my stuff and normally do not need to use the GUI.
Pre-conditions for getting this to work is that you have MQTT Binding (version 2) installed.

1. Hardware Install
===============
Nice tutorial for programming and hardware installation of ratgdo

2. Flashing
=========
Use the MQTT flash image, my ratgdo is version 2.57

3. Setting up ratgdo
================
Find your ratgdo IP address for your LAN configuration, log in, and change the setup parameters (see below)

Note: The following names will found in your openHAB MQTT setup again:
MQTT Topic Prefix: ratgdo
Device Name: admin
Those two will be concatenated and used in the channel setup: ratgdoadmin


Screen Shot 2024-02-11 at 10.38.35 AM

4. Setting up thing defintion: mqtt.thing
================================

Bridge mqtt:broker:mosquitto "Mosquitto" [
	host="openhab",
	port=1883,
	secure=false,
	username="openhabian",
	password="xxxxxxxx",
	clientID="openHAB_NUC"
]

{
//****************************************************************
//****************************************************************

//***************************************************
// ratgdo Garage Door opener interface
//***************************************************
Thing topic ratgdo_cmd "ratgdo_1_cmd" @ "ratgdo garage cmd" {
Channels:
 Type switch : doorstop     "Switch Garage Door"
 [
    	commandTopic="ratgdoadmin/command/door", on="stop", off="stop"
 ]
 Type switch : door     "Switch Garage Door"
 [
     	commandTopic="ratgdoadmin/command/door", on="open", off="close"
 ]
 Type switch : light     "Switch Light"
 [
    	commandTopic="ratgdoadmin/command/light", on="on", off="off"
 ]
 }
Thing topic ratgdo_status "ratgdo_1_status" @ "ratgdo garage status" {
Channels:
Type string : online "Online"
[
     	stateTopic="ratgdoadmin/status/availability"
]
Type string : light "on"
[
     	stateTopic="ratgdoadmin/status/light"
]
Type string : obstruction "on"
[
     	stateTopic="ratgdoadmin/status/obstruction"
]
Type contact : doorC "on"
[
     	stateTopic="ratgdoadmin/status/door",
    	closed="closed", open="open"
]
Type string : door "on"
[
    	stateTopic="ratgdoadmin/status/door"
]
Type string : lock "on"
[
     	stateTopic="ratgdoadmin/status/lock"
]
}

5. Setting up items: garagedoor.items
===============================

Switch        GarageDoor_Opener        "Open/Stop/Close Garage Door"     <garagedoor>  (gGarageDoor)
Contact       GarageDoor_Closed        "Garage Door Closed/Open"		<garagedoor>   (gGarageDoor)
Switch        GarageDoor_IsOpening     "Garage Door opening"            <garagedoor>   (gGarageDoor)
String        GarageDoor_StatDoor      "Garage Door status [%s]"       	<garagedoor>   (gGarageDoor)                  { channel="mqtt:topic:mosquitto:ratgdo_status:door" }
Switch		  GarageDoor_Stop		   "Stop Garage door movement"		<garagedoor>   (gGarageDoor)                  { channel="mqtt:topic:mosquitto:ratgdo_cmd:doorstop" }
Switch		  GarageDoor_OpenClose	   "Open/Close MQTT command"		<garagedoor>   (gCDcmdg,GarageDoor)           { channel="mqtt:topic:mosquitto:ratgdo_cmd:door" }
Switch        GarageDoor_Light         "On/Off Garage Door Light"       <light>        (gCDcmd,gGarageDoor)           { channel="mqtt:topic:mosquitto:ratgdo_cmd:light" }
String        GarageDoor_StatLight     "Garage Light is [%s]"           <light>        (gRestore,gGarageDoor)         { channel="mqtt:topic:mosquitto:ratgdo_status:light" }
String        GarageDoor_StatObstruct  "Garage Obstruction [%s]"        <garagedoor>   (gRestore,gGarageDoor)         { channel="mqtt:topic:mosquitto:ratgdo_status:obstruction" }
String        GarageDoor_StatLock      "Garage Door is [%s]"            <garagedoor>   (gRestore,gGarageDoor)         { channel="mqtt:topic:mosquitto:ratgdo_status:lock" }
String        GarageDoor_StatOnline    "Garage Door is [%s]"            <garagedoor>   (gRestore,gGarageDoor)         { channel="mqtt:topic:mosquitto:ratgdo_status:online" }
Switch        GarageDoor_Light_FB      "Garage Door Light feedback" 	<light>        (gGarageDoor)

6. Setting up sitemap: home.sitemap
==============================

Text label="Garage" icon=garage_detached
{
	Default item=GarageDoor_Opener
	Default item=GarageDoor_StatDoor
	Default item=GarageDoor_Light
	Default item=GarageDoor_StatLight
	Default item=GarageDoor_StatObstruct
	Default item=GarageDoor_StatOnline
	Default item=GarageDoor_StatLock
}

7. Setting up some rules to tie everything together: garage.rules
====================================================

// ********************************************************
// Garage Door control
// ratgdo sends following strings: closed,open,opening,closing,stopped
// ********************************************************
rule "Rule Garage Door control"
when
	Item GarageDoor_Opener received command
then
	Thread::sleep(20)	// wait a little for state to update
	if (GarageDoor_Opener.state == ON)		// this is the command from GUI (or another rule)
	{
		switch GarageDoor_StatDoor.state.toString			// depending which state garage door is in:
		{
			case "closed":
			{
				GarageDoor_OpenClose.sendCommand(ON)		// send MQTT open command
				GarageDoor_IsOpening.sendCommand(ON)		// remember on its way to open (if stopped)
			}
			case "open":
			{
				GarageDoor_OpenClose.sendCommand(OFF)		// send MQTT close command
				GarageDoor_IsOpening.sendCommand(OFF)		// remember on its way to close (if stopped)
			}
			case "opening":
			{
				GarageDoor_Stop.sendCommand(ON)				// stop movement (during opening)
				GarageDoor_Stop.postUpdate(OFF)				// toggle button on GUI to off
			}
			case "closing":
			{
				GarageDoor_Stop.sendCommand(ON)				// stop movement (during closeing)
				GarageDoor_Stop.postUpdate(OFF)				// toggle button on GUI to off
			}
			default:										// would get here for "stopped" status from ratgdo
			{
				if (GarageDoor_IsOpening.state == ON)
				{
					GarageDoor_OpenClose.sendCommand(OFF)	// send MQTT close command (opening was stopped)
					GarageDoor_IsOpening.sendCommand(OFF)	// remember on its way to close (if stopped)
				}
				else
				{
					GarageDoor_OpenClose.sendCommand(ON)	// send MQTT open command (closing was stopped)
					GarageDoor_IsOpening.sendCommand(ON)	// remember on its way to open (if stopped)
				}
			}
		}
		GarageDoor_Opener.sendCommand(OFF)					// reset the command from GUI (or another rule)
	}
end

// ********************************************************
// Garage Door Light status update
// ********************************************************
rule "Rule Garage Light status update"
when
	Item GarageDoor_StatLight changed
then
	if (GarageDoor_StatLight.state.toString == "off")
	{
		GarageDoor_Light.postUpdate(OFF)
		GarageDoor_Light_FB.postUpdate(OFF)
	}
	if (GarageDoor_StatLight.state.toString == "on")
	{
		GarageDoor_Light.postUpdate(ON)
		GarageDoor_Light_FB.sendCommand(ON)
	}
end

// ********************************************************
// Garage Door status update
// ********************************************************
rule "Rule Garage status update"
when
	Item GarageDoor_StatDoor changed
then
	if (GarageDoor_StatDoor.state.toString == "closed")
	{
		GarageDoor_Closed.postUpdate(CLOSED)
	}
	if (GarageDoor_StatDoor.state.toString == "open")
	{
		GarageDoor_Closed.postUpdate(OPEN)
	}
end

// ********************************************************
// Garage Door closed actions
// ********************************************************
rule "Rule Garage Door closed"
when
	Item GarageDoor_Closed changed to CLOSED
then
	Light_Hallway_Kitchen.sendCommand(ON)
end

8. Sitemap control
===============

See screen shot below, the first switch item (“Open/Stop/Close Garage Door”) is used in the rules file and is your main control. When you switch it on, it will automatically switch off. The control of the garage door is similar to your hardware button on the wall:

Garage state:		Action when switch is actuated:
closed			    Garage door will open
open				Garage door will close
closing or opening	Garage door will stop moving
stopped			    Garage door will to move opposite direction of prior movement (i.e. when closing was stopped, it will now open)

This setup is probably not the most elegant solution, but it works for me.
You can also use the generated “GarageDoor_Closed” contact item to trigger other actions. In my case I turn on the hallway light coming into the house.

Have fun…

I’m off-topic, but there’s one particular reason that I encourage people to upgrade from OH2: the log4j vulnerability that was only patched in OH3.

You might want to give a fresh OH4 a try. You should be able to copy your text files into a clean installation and make a few edits to get it all working exactly the same as before (if not better). If it’s too much hassle, you can just go back to your OH2 installation.

Alternatively, you can set up OH4 on a different server and use the Remote binding to access your OH2 server while transferring things over.

Why not use receivedCommand instead? That’s the command sent to the Item and you don’t have to wait for the Item to update before you use it. A sleep makes the rule brittle and more likely to fail in weird ways.

If receivedCommand works, change the trigger to received command ON and you won’t even need the if statement at all.

Disable autoupdate on this Item and sending it a command won’t change it’s state. Then you don’t need to reset it back to OFF after every command.

Even with autoupdate, from what I can tell it’s not required to set the Item back to OFF. The ON command will go out to the binding and send the message even if the Item is already ON.

Since the Channel only has a commandTopic, it might make sense to replace this entire Item and that Channel with a call to the publishMqtt Action instead.

Similarly, here you can either set autoupdate to false so the Item doesn’t change state or just leave it ON. Usually for a momentary button press like this one uses a Switch element in the sitemap with a button. Every time you press the button the ON command gets sent and it really doesn’t matter what state the Item is in.

This part confuses me somewhat. I think you might have a misunderstanding on how MQTT Channels work. One Channel can be configured to publish to a commandTopic and subscribe to a statusTopic. You don’t need this GarageDoor_StatLight Item (and it’s corresponding Channel at all. Just add the stateTopic for the status Channel to the “Switch Light” Channel and the one GarageDoor_Light Item can be used to see the sate of the light and control it. This eliminates the need for that extra Channel, the GarageDoor_Light_FB Item and the “Rule Garage status update” rule.

Assuming the following (give that a Thing is supposed to represent a single device, it seems odd to split this into two separate Things):

Thing topic ratgdo "ratgdo_1_cmd" @ "ratgdo garage cmd" {
Channels:
  Type switch : light     "Switch Light"
  [
    stateTopic="ratgdoadmin/status/light" commandTopic="ratgdoadmin/command/light", on="on", off="off"
  ]
 Type switch : online "Online"
 [
    stateTopic="ratgdoadmin/status/availability"
 ]
 Type string : obstruction "on"
  [
    stateTopic="ratgdoadmin/status/obstruction"
  ]
 Type string : door "on"
  [
    stateTopic="ratgdoadmin/status/door"
  ]
  Type string: doorOpen "on"
  [
    stateTopic="ratgdoadmin/status/door" transformationPattern="MAP:mapFile,map"
  ]
  Type string : lock "on"
  [
    stateTopic="ratgdoadmin/status/lock"
  ]
}

The mapFile.map goes in the transformations folder and contains

closed=CLOSED
=OPEN

“closed” will map to CLOSED and all other states will map to OPEN

Items become

Switch        GarageDoor_Opener        "Open/Stop/Close Garage Door"     <garagedoor>  (gGarageDoor)
Contact       GarageDoor_Closed        "Garage Door Closed/Open"		<garagedoor>   (gGarageDoor)                  { channel="mqtt:topic:mosquitto:ratgdo:door" }
Switch        GarageDoor_IsOpening     "Garage Door opening"            <garagedoor>   (gGarageDoor)
String        GarageDoor_StatDoor      "Garage Door status [%s]"       	<garagedoor>   (gGarageDoor)                  { channel="mqtt:topic:mosquitto:ratgdo:door" }
Switch        GarageDoor_Light         "On/Off Garage Door Light"       <light>        (gCDcmd,gGarageDoor)           { channel="mqtt:topic:mosquitto:ratgdo:light" }
String        GarageDoor_StatObstruct  "Garage Obstruction [%s]"        <garagedoor>   (gRestore,gGarageDoor)         { channel="mqtt:topic:mosquitto:ratgdo:obstruction" }
String        GarageDoor_StatLock      "Garage Door is [%s]"            <garagedoor>   (gRestore,gGarageDoor)         { channel="mqtt:topic:mosquitto:ratgdo:lock" }
String        GarageDoor_StatOnline    "Garage Door is [%s]"            <garagedoor>   (gRestore,gGarageDoor)         { channel="mqtt:topic:mosquitto:ratgdo:online" }

I’d probably make the status Items like Online, Obstruct, et al be Switch Items but left them as Strings here.

The sitemap becomes:

Text label="Garage" icon=garage_detached
{
	Default item=GarageDoor_Opener
	Default item=GarageDoor_Closed
	Default item=GarageDoor_Light
	Default item=GarageDoor_StatObstruct
	Default item=GarageDoor_StatOnline
	Default item=GarageDoor_StatLock
}

And then the rules become:


// Garage Door control
// ratgdo sends following strings: closed,open,opening,closing,stopped
rule "Rule Garage Door control"
when
	Item GarageDoor_Opener received command ON
then

    // 1-2-3 Design Pattern
    // 1. Always run the rule

    // 2. Calculate what needs to be done
    val action = getActions("mqtt","mqtt:broker:mosquitto")

    // Default to the opening/closing states
    var cmd = 'stop'
    var isOpening = OFF

    switch GarageDoor_StatDoor.state.toString {
        case "closed":  { cmd = 'open'   isOpening = ON }
        case "open":    cmd = 'close'     // isOpening is already OFF, no need to set it again
        case "stopped": {
            if(GarageDoor_IsOpening.state == ON)  cmd = 'close'. // isOpening is already OFF
            else { cmd = 'open' isOpening = ON }
        }
    }

    // 3. Do it
    action.publishMQTT('ratgoadmin/command/door', cmd, false)
    GarageDoor_IsOpening.postUpdate(ON)
end


// Garage Door closed actions
rule "Rule Garage Door closed"
when
	Item GarageDoor_Closed changed to CLOSED
then
	Light_Hallway_Kitchen.sendCommand(ON)
end

Obviously I just typed in the above and there may be typos. But it should give some ideas on how to make the configuration much less complex.

Note that for OH 3 or OH 4 I’d strongly suggest making the rule a Rule Template that users can just install and use instead of copy/paste/edit. A corresponding UI Widget on the marketplace that users can just install and use would be cool too. But none of that is available in OH 2.

Eventually something will break and the only way to fix it will be to upgrade. It’s far easier to do an upgrade when you are not under the gun and can do it in your own time without any pressure than when everything is broken and the rest of the family is upset.

The fix for that was backported to 2.5.12 IIRC.

There really isn’t anything here that is OH 2.5 specific. I think the rules and the MQTT configs would work as written in OH 3 or 4. There are a bunch of new features in OH 4 that could make this even less complex though.

1 Like

Oh, good stuff. I thought it couldn’t be backported since Bintray was sunsetted (or something like that). But I don’t pretend to know enough about how any of this stuff works, and your memory is significantly better than mine (just take my word for it). So, I choose to believe you over me. :wink:

That was a different issue. We lost all the artifacts for OH prior to 2.5.12 because of bintray. But we were able to backport that very significant fix at least as far as 2.5.12. People running anything older than that though, well, they don’t care about security in the first place. If they did they would be running a more recent version.

1 Like

@rpwong Thank you for your suggestion to upgrade, I have been looking at it for a while and still not found the time for it…

@rlkoshak Thank you for your valuable feedback, I greatly appreciate the time you spend to teach all of us to simplify the code. I will try that step by step and learn :wink: