Rollershutter position state update to Dimmer when fully opened or closed

Hello,

I am new to OH (running 3.2.0 with OpenHABian on x86 hardware) and I am trying to migrate my devices from another platform to OH. I started by adding my Fibaro Walli Rollershutter (FIBEFGWREU-111) devices using an Aeotec Z-Stick 5+. Technically everything works fine (I guess…)

  • Z-Wave Device was added as Thing to OH
  • Used “Add Equipment to Model” in Thing Channels
  • Equipment created an Item with several Points in my Model. One is ff_of_rollershutter_control, which is the rollershutter Control. I then added an additional Point ff_of_rollershutter_position as Dimmer, the get/set a position as percentage value.

The problem however is the following:

  1. When moving, the position is not updated in real-time in the Dimmer, when movement is stopped, position is updated after some delay. Is there a chance to get a real-time position update (i.e. every 1s when moving)?

  2. When it is fully opened or fully closed the position value is not updated at all. It remains the last value were it was stopped.

Example: Blinds were stopped at 55 % and command UP was sent; this is what I can see in events.log:

2022-06-26 18:49:21.357 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'ff_of_rollershutter_control' received command UP
2022-06-26 18:49:21.360 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'ff_of_rollershutter_control' predicted to become UP
2022-06-26 18:49:21.365 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'ff_of_rollershutter_control' changed from 55 to 0 
2022-06-26 18:49:21.947 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'ff_of_rollershutter_electricmeter_watts' changed from 116.3 to 0
2022-06-26 18:49:22.102 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'ff_of_rollershutter_position' changed from 55 to 59
2022-06-26 18:49:22.103 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'ff_of_rollershutter_control' changed from 0 to 59
2022-06-26 18:49:24.814 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'ff_of_rollershutter_electricmeter1_watts' changed from 0 to 98.6

Note: “changed from 55 to 0” → 0 was the position before the 55 (blinds were fully closed). Now as it starts moving, there is one single update → value = 59.
When fully opened, it should have position value = 100, but this is never coming to OH, at least it is not shown in events.log.
When I now trigger a full close, the following happens:

2022-06-26 18:53:02.573 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'ff_of_rollershutter_control' received command DOWN
2022-06-26 18:53:02.576 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'ff_of_rollershutter_control' predicted to become DOWN
2022-06-26 18:53:02.580 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'ff_of_rollershutter_control' changed from 59 to 100
2022-06-26 18:53:03.516 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'ff_of_rollershutter_position' changed from 59 to 95
2022-06-26 18:53:03.517 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'ff_of_rollershutter_control' changed from 100 to 95
2022-06-26 18:53:06.111 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'ff_of_rollershutter_electricmeter1_watts' changed from 0 to 116.4
2022-06-26 18:53:25.891 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'ff_of_rollershutter_electricmeter1_watts' changed from 116.4 to 0

As you can see here, the first update is the value it had when starting (100), which was never set in OH before. Next update is then a first position update (95). The full close state however is never received.

Additional info: the position value is updated, when I press the stop button afterwards.

Any idea on this? Is there some mis-configuration in my Things, Items, what ever?

Thanks and regards from Germany
Markus

Sorry, I already found an issue in configuration related to the “Command poll period” setting of the rollershutter Thing.
When set this setting to 15000 it delays a “poll after command” to 15s, which s better, because then the first state update is delayed. Unfortunately 15s is not enough for a full up/down cycle, but 15000 seems to be the highest possible value.

Eh, additional info: When using the physical buttons, the state after a full open/close is updated correctly. The issue only happens when using the UI.
Is there a chance to implement a kind of “real-time” update using scripting? Or at least to execute a poll after approx. 20s of time after UP/DOWN command in UI?

The question to ask is why the Fibaro does not report what you want, and can you persuade it do so.
Polling devices over z-wave is a bad idea.in general, better to have them tell you when something changes.

If this device supports REFRESH command, you could set up a rule to execute a REFRESH after N seconds.

Thanks for your reply, so it is a FIBARO issue. Is there any chance to set the repoll interval to a value higher 15000? Is this a limit from fibaro or from OH?

I solved it by using a rule with a script to trigger the REFRESH command until position is not changed anymore.

To use it, create a group and add all rollershutter control-elements to that group. In my case that group is named “grp_dev_rollershutters”. Use this group in a new rule “When an member of grp_dev_rollershutters was updated” and as then use a ECMAScript V11 with the following coding:

console.debug("rollershutters_refresh_position_while_moving > script: Start");

var pollingInterval = 5000;  // Polling interval in milliseconds
var maxExecutionTime = 60000;  // Maximum execution time in milliseconds


var executionTime = + new Date();
var cancelationTime = executionTime + maxExecutionTime;
console.info("Execution started at " + executionTime + ", so execution is canceled at or after " + cancelationTime);

var eventItem = "";
var eventState = "";
var eventType = "";

var itemName = "";
var itemState = "";
var itemStatePrevious = "";
var itemDirection = "";
var itemPosition = -1;
var itemPositionPrevious = -1;

var startTimer = false;


if(typeof event !== 'undefined') {
  eventType = String(event.type);
  eventItem = String(event.itemName);
  eventState = String(event.itemState);
  
  console.info("Event parameters: type=" + eventType + " item=" + eventItem + ", state=" + eventState);
} else {
  console.warn("No event for rule's scripting in rollershutters_refresh_position_while_moving");
  
  // For debugging ("Run now"), use static event parameters
  eventType = "ItemStateEvent";
  eventItem = "ff_of_rollershutter_control";
  eventState = "42";
}


if(eventType === "ItemStateEvent") {
  // Only handle ItemStateEvents here
  var item = items.getItem(eventItem);
  if(typeof item !== 'undefined') {
    itemName = item.name;
    itemState = item.state;
    
    // There are two possible eventStates (direction as string or position as number)
    if(eventState === "UP" || eventState === "DOWN") {
      // Item received UP or DOWN command, this is always the initial trigger command
      console.info("Item " + item.name + " started moving " + eventState + " and current state value is = " + itemState);

      itemDirection = eventState;
      
      // Start a timer to refresh the item state
      startTimer = true;
    } else if(!isNaN(parseInt(eventState))) {
      // Item received a number value, there a two possible event sources: Update of state (i.e. after REFRESH) or an initial position command
      // Read cached values (if any)
      itemStatePrevious = cache.get(eventItem+"_eventItemPosition");
      itemDirection = cache.get(eventItem+"_eventItemDirection");
      
      // When cache is empty, this is the initial position command, which means there is no previous value (in cache)
      if(itemStatePrevious === null && itemDirection === null) {
        itemStatePrevious = '-1';
        itemDirection = 'UNKNOWN';
      }
      
      // Get position from item state(s)
      itemPosition = parseInt(itemState);
      itemPositionPrevious = parseInt(itemStatePrevious);
      
      if(itemDirection === '' && itemPositionPrevious >= 0) {
        if(itemPosition < itemPositionPrevious) {
          itemDirection = 'DOWN';
        } else {
          itemDirection = 'UP';
        }
      }
      console.debug("itemState = " + itemState + ", itemStatePrevious = " + itemStatePrevious + ", itemDirection = " + itemDirection);
      console.info("Item " + item.name + " is (probably) moving " + itemDirection + " with current state position value "+itemPosition+" (previous position="+itemPositionPrevious+")");
      
      if(itemPositionPrevious !== itemPosition) {
        // Items position changed compared to previous known position, we are assuming it is still moving ...
        // Refresh item using defined polling interval, but make sure we are before the cancelation time
        if(cache.get(eventItem+"_eventItemCancelationTime") !== null) {
          // get cancelation time from cache
          cancelationTime = cache.get(eventItem+"_eventItemCancelationTime");
        } else {
          // use cancelation time as defined in the beginning ...
        }
        
        if(executionTime < cancelationTime) {
          // Add current position to cache and prepare REFRESH command
          console.info("Going to REFRESH item after defined polling interval ...");
          startTimer = true;          
        } else {
          // Cancelation time is exceed, no more executions
          console.info("Cancelation time is exceed, aborting ...");
          startTimer = false;
        }
      } else {
        console.info("Items position value does not differ from previous, assuminig item stopped moving ...");
        startTimer = false;
      }
    } else {
      console.info("Skipping execution because of unhandled EventState " + eventState + " ...");
      startTimer = false;
    }
    
    if(startTimer) {
      console.info("Updating cached values and starting REFRESH timer. See you again in " + (pollingInterval/1000) + " seconds ...");
      cache.put(eventItem+"_eventItemCancelationTime", cancelationTime);
      cache.put(eventItem+"_eventItemName", itemName);
      cache.put(eventItem+"_eventItemDirection", itemDirection);
      cache.put(eventItem+"_eventItemPosition", itemState);
      
      // Start a timer to refresh the item state after the defined polling interval
      // Note: refreshing the item will trigger a new ItemStateEvent, so script will be executed again, but with cached values
      var timer = setTimeout(() => {
        item.sendCommand("REFRESH");
      }, pollingInterval);
    } else {
      // No need for further executions of thins one... Clean-up the cache
      console.info("Cleaning up cache before ending ...");
      cache.remove(eventItem+"_eventItemCancelationTime");
      cache.remove(eventItem+"_eventItemName");
      cache.remove(eventItem+"_eventItemDirection");
      cache.remove(eventItem+"_eventItemPosition");
    }
  } else {
    console.info("Skipping execution because of unknown Item " + eventItem);
  }
} else {
  console.info("Skipping execution because of unhandled EventType " + eventType);
}

console.debug("rollershutters_refresh_position_while_moving > script: End");

Please do not blame me, if that script it not that perfect, these are my first steps in OpenHAB and it works for me.

So now, when the rollershutter is triggered from UI with UP/DOWN buttons or with a position value (0-100) from a Dimmer item or from HomeKit, the device is REFRESHed according to value of variable pollingInterval. This happens as long as the position value of the previous execution and the current execution is equal (or if a defined timeout is reached).

Note: If a device takes usally longer than 60 seconds for a full open or close cycle, you have to increase the variable value of maxExecutionTime.

Note 2: Feel free to remove all “console” commands, as these are only required for debugging purposes.

Maybe this will help others who have the same problem.

By the way, the rule is not triggered, when the rollershutter is operated using the physical buttons. I guess the Fibaro is not sending anything when it starts moving, but only when it stops.
But in this case the item will be updated automatically after moving, so this is okay for me.