[SOLVED] Looking for Ideas on Garage door Solution

The switch opens the garage door, the feedback is from the Garage door closed contact.
At the moment the switch has a 1 second expiry as it is a momentary switch for the garage door opener.

I want to create an item so it can be reflected in Apple Homekit as at the moment the switch returns to off after the one second, even if the door is open. I want the homekit switch to reflect the status of the Door (from the garagedoorCcontact)

Switch GarageDoorSW             "Garage Door SW"                                 <garagedoor>  [ "Switchable" ]         {channel="mqtt:topic:Garage_Door:Garage_Door_SW" ,expire="1s,command=OFF",autoupdate="false" }
Contact GarageDoorOContact      "Door Open Contact [%s]"                         <garagedoor>                           {channel="mqtt:topic:Garage_Door:G_Door_O_Contact"}
Contact GarageDoorCContact      "Door Closed Contact [%s]"

To solve the CLOSED, OPENING, OPEN, CLOSING, CLOSED issue:

Created a new Channel in my Garage_Door MQTT Items in Paper UI:

Created a New Item in my Items file:

Added it to my Sitemap:

Added the rule:

//GARAGE DOOR STATE
 
rule "Garage door opening"
 
 when
 
 Item GarageDoorCContact changed to OPEN  //Door opening
 
 then
 
 GarageDoorCContact1.postUpdate( "OPENING" )
 
 end
 
 rule "Garage door closing"
 
 when
 
 Item GarageDoorOContact changed to CLOSED //Door closing
 
 then
 
 GarageDoorCContact1.postUpdate(  "CLOSING" )
 
 end
 
rule "Garage door closed"
 
when
 
 Item GarageDoorCContact changed to CLOSED  // Door closed
 
 then
 
 GarageDoorCContact1.postUpdate(  "CLOSED" )
 
 end
 rule  "Garage door open"
 
 when
 
 Item GarageDoorOContact changed to OPEN  //Door open
 
 then
 
 GarageDoorCContact1.postUpdate( "OPEN" )
 
 end

This resulted in the desired output in my UI:




OK, so Switch controls the opening of the door. A Contact reflects the state of the door. Thatā€™s what you have now. So what do you want? If you are trying to combine the Switch and Contact into one Item than the answer is you canā€™t.

Yes thats what i want! I want some sort of feedback through Apple Home app for the state of the door.

When i had the Chamberlain MYq binding ported through the garage switch reflected the state of the door

:disappointed:

A Switch can only be ON or OFF. Period. And you have the Switch configured to automatically turn OFF after a second. There is no possible way that you can use this same Switch to represent the OPEN/CLOSE state of the Garage door. I donā€™t know how MyQ binding does it but it either didnā€™t use a Switch Item, or it used ON to represent the door is OPEN and OFF to represent that the door is CLOSED. But I donā€™t see how, even with this configuration, that you can both control the garage door and represent itā€™s state in one Item. Maybe with autoupdate=false, but you are still left with the fact that the Item is a Switch, not a Contact.

OK thanks for your insight, will have to just add a [ ā€œContactSensorā€ ] in my items file on the closed contact until i figure another way.

Well, almostā€¦
The push button is wired to the IHC controller (input module). The IHC controller sends 868mhz signal to a IHC wireless dimmer. I do have IHC wireless push buttons as well. So everything goes through the controller wireless.
I do see youĀ“re points, though IĀ“m still positive this should be possible.
But letĀ“s stick to the rollershutter (garagedoor) first. Then I might have been convinced never to try a dimmer, afterwards :smiley:

"Software Rollershutter"
I have measured the time it takes to open and close the garagedoor.
22.5 seconds from fully closed to fully open.
19.5 seconds from fully open to fully closed.
I assume all timings should be in done in ms?

In order to ā€œrecordā€ the direction, is there any good way to do this, or is this by using proxyitems, and hope it never gets out of sync? (or perhaps resync each time the garagdoor reach a sensor, which would be the mostly used way normally (fully open or fully closed).

In one of your previous messages above you wrote

Since it takes 22500ms to fully open, I assume for every 2250ms, it should postUpdate the Rollershutter item at a step of 10%?

What ever makes the math easiest for you. It ultimately doesnā€™t matter.

See the state machine replies I made showing how to use the events and changes to the contacts to determine what direction the door is going in. In short, Iā€™ve already told you how to do that part on post 13 above. Looking for Ideas on Garage door Solution

Absolutely. Thatā€™s what ā€œrecalibrate the percent to 0 or 100ā€ that I said multiple times above means.

Plus you have a little bit of calculations to do when the door stops because it will not have traveled for a full 2250ms. So what I would do to make it easy is just take a time stamp at the beginning of motion. Periodically check how long the door has been moving (Iā€™d probably check every 500 msec so itā€™s nice and responsive but you can experiment). Then you subtract the current timestamp in milliseconds from the timestamp taken when the door started moving divided by the total amount of time it takes for the door to open to get the percentage. That eliminates the special case when you stop the door.

var Timer timer = null
var Number start_time = 0
val calcPercent = [ Number start_time |
    val OPENTIME = 22500
    val CLOSETIME = -19500 // we count up from closed, count down from opened

    val delta = now.millis - start_time
    
    return (delta / if(GarageDoor.state == "OPENING") OPENTIME else CLOSETIME).intValue
]

rule "door started moving"
    Item GarageDoor changed to OPENING or
    Item GarageDoor changed to CLOSING
than
    start_time = now.millis

    timer = createTimer(now.plusMillis(500), [ |
       val percent = calcPercent.apply(start_time)
       GarageDoorPercent.postUpdate(GarageDoor.state + percent)
       if(GarageDoor.state == "OPENING" || GarageDoor.state == "CLOSING"){
            timer.reschedule(now.plusMillis(500))
    ])
end

rule "door stopped"
    Item GarageDoor changed to STOPPED or
    Item GarageDoor changed to CLOSED or
    Item GarageDoor changed to OPENED
than
    timer?.cancel

    var newState = 0 // covers the CLOSED case
    switch(GarageDoor.state.toString){
        case "OPENED": newState = 100
        case "STOPPED": newState = calcPercent.apply(start_time)
    }

    GarageDoorPercent.postUpdate(newState)
end

The above was just typed in. There are almost certainly errors.

I keep looking at that post and I dont get itā€¦
First of all, its not Rules DSL. (It still seem quite logic anyway).
Second, the part:

# Door is in motion
    elif currState != "STOPPED":
        newState = "STOPPED"

    # Door is partially open but not moving
    else:
        newState = "OPENING" if prevState == "CLOSING" else "CLOSING"

is really confusingā€¦
currState not equal to ā€œSTOPPEDā€. Where did STOPPED come from? I assume its suppose to be a value string like CLOSED and OPENED from the sensors?

And I cant see how the ā€œOPENINGā€ and ā€œCLOSINGā€ is beeing defined either.

It seems like the logic is turned upside down, and something is missingā€¦ But itĀ“s probably just me who dont get it.

Before we get to that line weā€™ve tested whether the door is OPENED or CLOSED. Itā€™s neither of those so we know that the door is in motion, either opening it closing. The button was pressed to trigger this rule so we know that the door is now stopped and partially open.

When you press the button and the door is in motion, the door becomes stopped.

Stopped indicates the door is not in motion but it is neither fully open not fully closed either.

They after just Strings. You can make them anything you want. The important thing is you come up with names for reach of the states and used those names to represent when the door is in a given state. Iā€™ve used:

  • ā€œCLOSEDā€: door is fully closed
  • ā€œOPENEDā€: door us fully opened
  • ā€œOPENINGā€: door is in motion in the opening direction
  • ā€œCLOSINGā€: door is in motion in the closing direction
  • ā€œSTOPPEDā€: door is not in motion but also not fully open not fully closed.

After a certain time, yes. But this timer isnĀ“t part of the rule? So in this rule, the door never stops, at least not untill it has reach an end (sensor)ā€¦ The door should be on the move, until ā€œsomethingā€ state it has stopped?

Hmmā€¦ My problem may be, that I thought this was a finished ruleā€¦ But am I right in assuming, this is just a principal, and therefore part of a rule?

So the CLOSED and OPENED isnĀ“t actual states from the sensors?

There is no timer. If the door is closed and you push the button. The door is no longer closed, itā€™s in motion. If you press the button again while itā€™s in motion the door stops moving. Itā€™s not closed yet, itā€™s just stopped.

Itā€™s all event driven.

Or the button is pressed when the door is moving.

Yes, ordering the button again is the something.

The logic is finished. The code is untested and may have bugs.

Look at the state table in part 13. That defined all the behaviors implemented by the rules. It defines all the states that the door can be in, including stopped. And it explains hi the door traditions from one state to another.

If you need to, go study state machines in general.

NONE of these a are states from the sensors. These are the states of our state machine representing the state of the garage door. They are made up strings. You could use ā€œfooā€ and ā€œbarā€ for all it matters.

The sensors and the button provide the events that are used to transition from one state to another state. Thatā€™s all.

Hmm simply dont understandā€¦ I do get the idea, but I dont see how to rewrite it to a working ruleā€¦

I also got another idea for detamin the directionā€¦
The sensors IĀ“ve got can be either open or closedā€¦ When bottom sensor is closed, the door is closedā€¦
Now IĀ“m thinkingā€¦ Byt the use of two proxyswicthes, wouldnĀ“t this be suitable for detamin the direction?

when 
   item bottom.sensor changed from CLOSED to OPEN
then
  proxy_opening.postUpdate (OPENING)

And the same for the top sensor:

when 
   item top.sensor changed from CLOSED to OPEN
then
  proxy_closing.postUpdate (CLOSING)

Or is it bad idea?

Unless there are syntax errors, b it already is a working rule. Itā€™s complete. It covers all the states. It handled all of the events. What needs rewriting?

Which is exactly what my existing rule above does. It just does it all in one rule.

And your proposal only handles the case where the door fully opens or fully closes every time you press the button. What happens when the door is opening and you press the button? It stops moving. Ovne might say it enters a STOPPED state. What happens when you press the button again? It starts closing. If there is any complexity in that rule itā€™s because it handles this too.

I dont see the actual sensors (and the button). (Or IĀ“m simply steering blindā€¦ Need to test it, but first I have to ā€œtranslate itā€ to dsl rules.

Yeah, I just had a second thought while having dinner and came to exact same conclusionā€¦ Thats a bad ideaā€¦
The direction has to be detamin from the buttonā€¦ And I think it would be best to persist this as well. I suspect mapdb would be suitable for this?

@when("Item DoorOpenedSensor changed") // sensor that is OPENED when door is fully open
@when("Item DoorClosedSensor changed") // sensor that is CLOSED when door is fully closed

...

    # Door is fully closed
    if items["DoorClosedSensor"] == CLOSED:
        newState = "CLOSED"

    # Door is fully opened
    elif items["DoorOpenedSensor"] == CLOSED:
        newState = "OPENED"
@when("Item DoorController received command")

Ahh as I saidā€¦ I was blind :frowning:

Can a var be sat equal to an item in rules dsl ?
I have a few problems getting this translated to rules dslā€¦ I think IĀ“m close, but I think there is a few problems setting the variables for currState and the Ā“global prevStateĀ“ at the bottom.

This is how it looks:

rule "Garage door status"

when 
      Item  GaragePortBottomSensor changed or
      Item  GaragePortTopSensor changed or
      Item  garage_bryggers_NV changed from OFF to ON
then
    var  newState = UNDEF
    var currState = GarageDoorState

           // Garage door fully closed
     if(GaragePortBottomSensor.state.toString == "CLOSED" ) {
        newState = "CLOSED" }
   else
      
          // Garage door fully open                             
      if(GaragePortTopSensor.state.toString == "CLOSED" ) {
        newState = "OPEN" }

   else
          // Door is in motion
      if(currState != "STOPPED") {
        newState = "STOPPED" }

   else
         // Door is partially open but not moving
      if(prevState == "CLOSING") {
        newState = "OPENING" }
    else {
        newState = "CLOSING" }     

         // Could use persistence for this, keep track of the previous state so we can handle the STOPPED case
        global prevState
        prevState = currState
        GarageDoorState.postUpdate(newState)
end


// Proxy items
// Switch         GarageDoorState

I tried commenting out the global cause it gave an errorā€¦

2019-11-27 23:29:59.448 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Garage door status': The name 'global' cannot be resolved to an item or type; line 33, column 9, length 6

Then I get this error when I start the garagedoor:

2019-11-27 23:31:01.592 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Garage door status': An error occurred during the script execution: Couldn't invoke 'assignValueTo' for feature JvmVoid:  (eProxyURI: garagedoor.rules#|::0.2.0.2.0.3::0::/1)

Yes but there rarely is a point to. You either already know the Item so just use the Item name directly, or you really want something from the Item like itā€™s name or state so you would assign that to a variable.

Note, that items["DoorState"] returns the state of the Item DoorState. It is not the Item DoorState itself. So you need to ser currState to GarageDoorState.state.toString.

prevState is a global variable. In Rules DSL, as youā€™ve seen before, you define a variable as a global by putting the var above the Rules. There is nothing special that you need to do to access it. In Python you need to tell it you are using a global variable. In short global prevState is meaningless in Rules DSL.

You get the error when you try to set prevState is because you never defined prevState. If you look at the Python code, even there prevState is defined before the Rule.

IĀ“m not sure how to do thisā€¦ I believe its suppose to be a val and not a var then like this?

    val currState = GarageDoorState.state.toString

Second
IĀ“d set the prevState as a val before the ruleā€¦ When I saved the rule, I got this issue:

2019-11-28 00:00:54.512 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'garagedoor.rules', using it anyway:

The field Tmp_garagedoorRules.prevState refers to the missing type Object

Assignment to final field

The field Tmp_garagedoorRules.prevState refers to the missing type Object

Right after (without saving) I got this, with no issue:

2019-11-28 00:00:54.910 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'garagedoor.rules'

This is the error I get, when I fire the rule:

2019-11-28 00:05:50.996 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Garage door status': An error occurred during the script execution: Cannot assign a value in null context.