Garage Gate Control

Hello,

I have a shelly connect to my garage gate, the shelly just gives impulses to change the state of the gate
if the gate is closed it will open and if it is open ist will close.
The shelly has also an extentoin module connected to a input that tells my if the gate is closed.

I successfully connected this to an switch to trigger the shelly and a contact to get the state.

My problem:
In the UI only want one item that only shows the state and can control it for example a switch, if on the gate is open and if of the gate is closed.
There is a hardware button on the gate to control the gate as well, if pressed to close the gate the contact in openhab gets updated.
Then the switch in the ui gets updated to the according state.
The the rule gets triggerd to close the gate, this tells the shelly to send an impulse an the gate opens again.

Do you have a suggestion how to solve this, or do I have to use two ui Items one for the status and one for triggering

What you need is to separate commands from status.
That’s simple enough, on individual Items you disable autoupdate.

But then you have another problem. If I’m understanding correct, the command is just single “push button”, there are no open/close commands to the Shelly, only “change”.
The problem is around the UI. You can build a switch-y widget to show Open and Closed status, and that will naturally give Open and Closed commands. Where you want all your ‘pushbutton’ commands to be the same.

I think this can be done with one Item -

  • Link a Switch Item to the shelly input contact channel (you may need a transform to convert contact to switch)
  • Disable autoupdate on the Item (now you can send any command you like but the state only follows the gate contact)
  • Link the Switch Item to the shelly switch channel - but with a transform that converts ON or OFF into ON commands only. (I guess the shelly takes care of making that into pulse? Else we can do it at openHAB)
  • Now you need a customized UI widget; maybe something that shows ON/OFF state as “Open/Closed” by transformation, a single button perhaps. Switch-y UI widgets don’t like commanding ON if state is already ON, but we already made it so we don’t care if command is on or off.

If it were me I’d do it with two Items and rules, but essentially the same process.

I’ve implemented exactly this multiple times in the past in multiple ways. You say UI but not which one. I’ll assume OH 3 MainUI.

As rossko57 recommends, I use two Items, an actuator Switch Item which acts like a button so its state is kind of meaningless and a sensor Contact Item which represents the open/closed state of my garage door.

See Example Custom List Widgets for the List Widget that I use. It uses expressions to change the appearance and contents of the widget based on the state of the Contact. Clicking on the widget sends a command to the Switch Item to trigger the opener.

Note, in OH 3.2 you will be able to find and install this widget from the marketplace. For now you’ll have to copy and paste the YAML into a custom widget under Developer Tools.

I’ve used a similar approach for the main widget. I’ve two garage door openers and a camera (though the camera isn’t working right now) so I’ve combined all three into a unified widget.

Again, the color, icon and text changes based on the Contact Item and clicking on the widget sends a command to the Switch Item to trigger the opener. I know I’ve posted the code for this widget somewhere but can’t remember where so here it is.

uid: garage_widget
tags:
  - card
  - garage
props:
  parameters: []
  parameterGroups: []
timestamp: Feb 12, 2021, 10:02:20 AM
component: f7-card
config:
  title: Garage Doors
slots:
  default:
    - component: f7-row
      slots:
        default:
          - component: oh-image
            config:
              item: GarageCamera_Image
              style:
                width: 100%
                height: auto
    - component: f7-row
      config:
        class:
          - justify-content-left
      slots:
        default:
          - component: f7-col
            slots:
              default:
                - component: oh-label-card
                  config:
                    footer: Small Garage Door Opener
                    action: command
                    actionItem: Small_Garagedoor_Opener
                    actionCommand: ON
                    label: '=(items.Small_Garagedoor_Sensor.state == "OPEN") ? "close" : "open"'
                    item: Small_Garagedoor_Sensor
                    icon: '=(items.Small_Garagedoor_Sensor.state == "CLOSED") ? "f7:house" : "f7:house_fill"'
                    iconColor: '=(items.Small_Garagedoor_Sensor.state == "CLOSED") ? "green" : "orange"'
          - component: f7-col
            slots:
              default:
                - component: oh-label-card
                  config:
                    footer: Large Garage Door Opener
                    action: command
                    actionItem: Large_Garagedoor_Opener
                    actionCommand: ON
                    label: '=(items.Large_Garagedoor_Sensor.state == "OPEN") ? "close" : "open"'
                    icon: '=(items.Large_Garagedoor_Sensor.state == "CLOSED") ? "f7:house" : "f7:house_fill"'
                    iconColor: '=(items.Large_Garagedoor_Sensor.state == "CLOSED") ? "green" : "orange"'

That should show you kind of how a widget like this would work.

The rule I have is pretty simple, though it depends on libraries from https://github.com/rkoshak/openhab-rules-tools as well as some personal libraries and Item metadata to get the name and amount of time a give door needs to be open before alerting.

triggers:
  - id: "1"
    configuration:
      groupName: DoorsStatus
      state: OPEN
    type: core.GroupStateChangeTrigger
  - id: "4"
    configuration:
      groupName: DoorsStatus
      state: CLOSED
    type: core.GroupStateChangeTrigger
conditions:
  - inputs: {}
    id: "2"
    label: The door's state didn't change to an UnDefType
    configuration:
      type: application/javascript
      script: >-
        event.itemState.class != UnDefType.class

        && event.oldItemState.class != UnDefType.class
    type: script.ScriptCondition
actions:
  - inputs: {}
    id: "3"
    configuration:
      type: application/javascript
      script: >
        var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Rules.Open Door Reminder");


        var OPENHAB_CONF = java.lang.System.getenv("OPENHAB_CONF");

        load(OPENHAB_CONF+'/automation/lib/javascript/community/timerMgr.js');

        load(OPENHAB_CONF+'/automation/lib/javascript/personal/alerting.js');

        load(OPENHAB_CONF+'/automation/lib/javascript/personal/metadata.js')


        this.timers = (this.timers === undefined) ? new TimerMgr() : this.timers;


        var reminderGenerator = function(itemName, name, when, sendAlert, timers){
          return function() {
            if(items[itemName] != OPEN) {
              logger.warn(itemName + " open timer expired but the door is " + items[itemName] + ". Timer should have been cancelled.");
            }
            else {
              sendAlert(name + " has been open for " + when);
              // Reschedule if it's night
              var tod = items["TimeOfDay"].toString();
              if(tod == "NIGHT" || tod == "BED") {
                logger.info("Rescheduling timer for " + name + " because it's night");
                timers.check(itemName, when, reminderGenerator(itemName, name, when));
              }
            }
          }
        }


        logger.debug("Handling new door state for reminder: " + event.itemName + " = " + event.itemState);

        if(event.itemState == CLOSED && this.timers.hasTimer(event.itemName)) {
          logger.debug("Cancelling the timer for " + event.itemName);
          this.timers.cancel(event.itemName);
        }

        else {
          var name = getName(event.itemName);
          var remTime = getMetadataValue(event.itemName, "rem_time");
          if(remTime === null) {
            logger.warn("rem_time metadata is not defined for " + event.itemName + ", defaulting to 60m");
            remTime = "60m";
          }
          logger.debug("Creating a reminder timer for " + event.itemName + " for " + remTime);
          timers.check(event.itemName, remTime, reminderGenerator(event.itemName, name, remTime, sendAlert, timers));
        }
    type: script.ScriptAction

These are clearly all customized for my use cases but you should be able to use them as examples to build on.