I created a set of rules to automate our roof roller shutters by using proxy items, so I can intercept UP/DOWN commands when the temperature is too low (e.g. when it’s freezing). The roller shutters are Fakro ARZ Z-Wave (although OpenHAB invariably reports them as Fakro ZWS12 Chain Actuator - but that’s another story).
In the morning, I use a sequence of trigger events (civil dawn start, sunrise start, sunrise end) to try to raise the roller shutters in case the outside temperature is still too low.
The rules get fired as expected, but I can’t prevent them from firing again (3 roller shutter open commands sent in a row, although the roller shutters are already open from an earlier attempt).
I tried to verify the state of the roller shutters and their proxy items, but I get inconsistent state information all the time. And that also shows up in the UI as the reported roller shutter state rarely matches the actual state.
Is this a limitation of the Z-Wave binding, or is there something else I could try?
Below you’ll find a very verbose "Proxy item received command"
rule:
import org.eclipse.smarthome.model.script.ScriptServiceUtil
// Send notification through the OH cloud binding:
val String notificationRecipient = "your_email_address_here"
/* All roof roller shutters are controlled by proxy items, in order to allow checking the outside temperature prior to operating the roller shutters.
*/
rule "Proxy item received command"
when
Member of gShutterProxy received command
then
val String ruleTitle = "Proxy roller shutter item received command"
val Number MIN_TEMP = 3.0|°C
// The proxy item has "Proxy_" as prefix to the 'real' item name:
val String itemName = triggeringItem.getName().substringAfter("Proxy_")
logInfo(ruleTitle, "Proxy Item '{}' (state = '{}' or '{}') received command '{}' --> Proxy for Item '{}'",
triggeringItem.getName(), triggeringItem.state, triggeringItem.state.toString, receivedCommand, itemName)
logInfo(ruleTitle, "Proxy Item '{}' - full details: [{}]",
triggeringItem.getName(), triggeringItem)
// Retrieve the 'real' item based on its name:
val GenericItem item = ScriptServiceUtil.getItemRegistry.getItem(itemName) as GenericItem
logInfo(ruleTitle, "Item '{}' (state = '{}' or '{}') - full details: [{}]",
item.getName(), item.state, item.state.toString, item)
switch (receivedCommand) {
case STOP: { // Directly forward 'STOP' command to the 'real' item
logInfo(ruleTitle, "Proxy Item '{}' received command '{}' --> Fowarding the command to Item '{}'",
triggeringItem.getName(), receivedCommand, itemName)
item.sendCommand(receivedCommand)
}
case UP,
case DOWN: {
if (Wx_OWM_Current_Temperature.state >= MIN_TEMP) {
// Here's my current failing attempt at avoiding multiple rule firings:
if (triggeringItem.state != item.state) {
logWarn(ruleTitle, "Proxy item '{" + triggeringItem.getName() + "}' state (" + triggeringItem.state
+ ") differs from real item '" + itemName + "' state (" + item.state + ") - Will nonetheless send '" + receivedCommand
+ "' to '" + itemName + "' as temperature ≥ " + MIN_TEMP)
sendNotification(notificationRecipient, "⚠️ Proxy item '{" + triggeringItem.getName() + "}' state (" + triggeringItem.state
+ ") differs from real item '" + itemName + "' state (" + item.state + ") - Will nonetheless send '" + receivedCommand
+ "' to '" + itemName + "' as temperature ≥ " + MIN_TEMP)
item.sendCommand(receivedCommand)
} else if ( ((receivedCommand == UP) && (item.state == 0)) || ((receivedCommand == DOWN) && (item.state == 100)) ) {
val String shutterCurrentStatus = ( if (item.state == 0) { "open" } else { "closed" } )
logInfo(ruleTitle, "Proxy Item '{}' received command '{}' --> already OK (Item '{}': state = {}, meaning {})",
triggeringItem.getName(), receivedCommand, itemName, item.state, shutterCurrentStatus)
sendNotification(notificationRecipient, "ℹ️ '" + itemName + "' already " + shutterCurrentStatus)
} else {
logInfo(ruleTitle, "Proxy Item '{}' received command '{}' --> Fowarding the command to Item '{}' as temperature ≥ {}",
triggeringItem.getName(), receivedCommand, itemName, MIN_TEMP)
sendNotification(notificationRecipient, "ℹ️ Sent '" + receivedCommand + "' to '" + itemName + "' as temperature ≥ " + MIN_TEMP)
item.sendCommand(receivedCommand)
}
} else {
logWarn(ruleTitle, "Proxy Item '{}' received command '{}' --> Discarding the command to Item '{}' as temperature < {}",
triggeringItem.getName(), receivedCommand, itemName, MIN_TEMP)
sendNotification(notificationRecipient, "⚠️ Cannot send '" + receivedCommand + "' to '" + itemName + "' as temperature < " + MIN_TEMP)
postUpdate(triggeringItem, item.state)
}
}
default: {
logError(ruleTitle, "Proxy Item '{}' received unexpected command '{}' -- ignoring",
triggeringItem.getName(), receivedCommand, itemName)
sendNotification(notificationRecipient, "⚠️ Cannot send unexpected command '" + receivedCommand + "' to '" + itemName + "'")
postUpdate(triggeringItem, item.state)
}
}
end
rule "Sunrise shutter rule NEW"
when
Channel "astro:sun:local:civilDawn#event" triggered START
or Channel "astro:sun:local:rise#event" triggered // In case we missed the civil dawn due to temperature below automation threshold
or Channel "astro:sun:local:noon#event" triggered // In case we missed the morning opening due to cold weather
then
val String ruleTitle = "SunriseShutterRule"
logInfo(ruleTitle, "Rule has been triggered")
gShutterProxy.allMembers.forEach[ s | s.sendCommand(UP) ]
end
rule "Sunset shutter rule NEW"
when
Channel "astro:sun:local:civilDusk#event" triggered END
then
val String ruleTitle = "SunsetShutterRule"
logInfo(ruleTitle, "Rule has been triggered")
gShutterProxy.allMembers.forEach[ s | s.sendCommand(DOWN) ]
end