First of all, please How to use code fences for your code.
Where possible, always use the method on the Item rather than the Action to sendCommand or postUpdate.
A switch statement would be a little bit cleaner for the first Rule.
switch(VacantionEventName.state) {
// case NULL: do nothing
case VacantionEvent.state.toString.length > 0: Vacantion.sendCommand(ON)
case VacantionEvent.state.toString == "",
case UNDEF: Vancantion.sendCommand(OFF)
}
I like the idea of adding a new entry to the calendar in response to the Manual Item changing as it keeps the calendar up to date. But if you don’t care about that, you could just moderately change your first Rule to include the Manual Item too.
rule "Change Vacantion"
when
System started or
Item VacantionEventName changed or
Item VacantionManual changed
then
var newState = Vacantion.state
// Let Manual take precedence over EventName by checking it first
if(VacantionManual.state == ON) newState = ON
else if(VacantionEventName.state == UNDEF) newState = OFF
else if(VacantionEventName.state.toString.length > 0) newState = ON
else if(VacantionEventName.state.toString == "") newState = OFF
Vacantion.sendCommand(newState)
end
You can further make this generic using Design Pattern: Associated Items.
Put all the event Switches into a Group, I’ll call it Events. Put the EventName and Manual Items in another Group, I’ll call it CalendarEvents.
import import org.eclipse.smarthome.model.script.ScriptServiceUtil
rule "A member of CalendarEvents changed"
when
System started or
Member of CalendarEvents changed
then
// We will calculate the new states for all the events in the Group
CalendarEvents.members.filter[ i | i.name.contains("EventName")].forEach[ eventName |
// Get the corresponding <event> and <event>Manual Items
val event = ScriptServiceUtil.getItemRegistry.getItem(eventName.replace("EventName", ""))
val manual = ScriptServiceUtil.getItemRegistry.getItem(eventName.replace("EventName", "Manual")
var newState = event.state
// Let Manual take precedence over EventName by checking it first
if(manual.state == ON) newState = ON
else if(eventName.state == UNDEF) newState = OFF
else if(eventName.state.toString.length > 0) newState = ON
else if(eventName.state.toString == "") newState = OFF
event.sendCommand(newState)
]
end
It’s just a little more complicated but now to add new Events you want to work with this Rule all you have to do is create the Items following the same naming scheme and add them to the CalendarEvents Group. You don’t have to copy the same code over again to work on a different set of Items.
The way it works is the Rule will trigger at System started or when any member of CalendarEvents changes state. The Rule will grab all of the Items that end in EventName from the CalendarEvents Group and loop over them. The first few lines of the loop gets the main event Item and the manual Item associated withe the eventName Item based on the naming scheme. Then we record the current state of the event Item. Next we have a series of if/else statements to determine whether the event Item needs to be ON or OFF based on the state of eventName (note that newState will be equal to the state event is already in for the case where eventName is NULL). Finally we send the calculated state to the event.