I have been PMed by someone to provide some samples and tips for writing groovy scripts, since there is so few documentation out there how to do it. I’ll post my answer here since it might also be interesting for others…
Hey there,
please have a look here, most of the things also apply, especially how to build the triggers etc. is a little bit cumbersome, but works:
Tips
- always use an outermost try-catch-block to realize if there are errors.
- Use logging, e. g.
def logger = LoggerFactory.getLogger("name-of-the-rule")
using importimport org.slf4j.LoggerFactory
- here is an explanation on how to reuse code blocks by extracting them to a separate script (and how to include it in other scripts: Groovy scripts: how to import another groovy file? - #8 by ndru )
- there are two nasty things I stumbled upon:
- there is a name clash of the automatically imported variable “action” which happens when you are inside a triggered rule… you can work around by creating a copy outside the rules (e. g. directly after the imports) like so:
def actionsCopy = actions
… and then using theactionCopy
instead:def mailActions = actionsCopy.get("mail","mail:smtp:mailSender") mailActions.sendHtmlMail("...emailadress", "...subject...","...content...")
- some of the core classes have a kind of class loading issue (inside the rules) and you have to call the constructor outside of the rules in the beginning of the script (e. g. after the imports) like so:
// This is a workaround for ClassNotFoundExceptions of the core classes. The need to be instantiated outside the rule // scope to be visible inside the rules for some reason new HTTP() new Transformation() new GroupItem("") new DecimalType()
- there is a name clash of the automatically imported variable “action” which happens when you are inside a triggered rule… you can work around by creating a copy outside the rules (e. g. directly after the imports) like so:
- see this post for details on the RuleHelper class for easy trigger creation
Samples
Rotate a RGB light through different colors on keypress:
def ruleSchlaZiBettTaster2 = new SimpleRule() {
@Override
Object execute(Action module, Map<String, ?> inputs) {
logger.info("Taster Bett2 betätigt")
if(items.get("HueGo_Toggle") == ON) {
logger.info("current state: " + items.get("HueGo_Color"))
HSBType hsb = items.get("HueGo_Color")
double hue = hsb.hue.doubleValue() + 50d
if(hue >= 360) {
hue = 0d
}
def color = new HSBType(new DecimalType(hue), hsb.saturation, hsb.brightness)
logger.info("sending HueGo color command: " + color)
events.sendCommand(itemRegistry.get("HueGo_Color"), color)
} else {
logger.info( 'Not switching Hue Go since its state is not ON: ' + items.get("HueGo_Toggle"))
}
}
}
ruleSchlaZiBettTaster2.name = "SchlaZiBettTaster2"
RuleHelper.itemAnyCommandTrigger(ruleSchlaZiBettTaster2, "SchlaZiBettTaster2", "Taster_SchlaZi_Bett2")
automationManager.addRule(ruleSchlaZiBettTaster2)
Automatically switch off a light after a given time (the kids always leave the light on
):
def ruleWCLicht1AutoAus = new SimpleRule() {
@Override
Object execute(Action module, Map<String, ?> inputs) {
if (items.get("Licht_WC_1") == OnOffType.ON) {
timer_wc_licht_1 = new Timer();
timer_wc_licht_1.schedule(new TimerTask() {
@Override
void run() {
events.sendCommand(itemRegistry.get("Licht_WC_1"), OnOffType.OFF)
}
}, 20 * 60 * 1000)
} else {
if (timer_wc_licht_1 != null) {
timer_wc_licht_1.cancel()
timer_wc_licht_1 = null
}
}
}
}
ruleWCLicht1AutoAus.name = "WCLicht1AutoAus"
RuleHelper.itemChangedTrigger(ruleWCLicht1AutoAus, "WCLicht1AutoAus", "Licht_WC_1")
automationManager.addRule(ruleWCLicht1AutoAus)
This is how you run stuff on OH start (when the script loads):
void scriptLoaded(Object notUsed) {
try {
if(items["BHKW_ServiceMailSent"] == NULL || items["BHKW_ServiceMailSent"] == UNDEF) {
events.sendCommand("BHKW_ServiceMailSent", "OFF")
}
} catch(Throwable t) {
logger.error("ERROR in BHKW startup rule: ${t.cause.toString()} - $t.message")
}
}
Retrieving and using JSON from a remote webservice:
String json = HTTP.sendHttpGetRequest("http://....URL....")
logger.debug(json)
if (json != null) {
events.postUpdate("BHKW_ThLeistung", Transformation.transform("JSONPATH", "\$.thLeistung", json))
...
EDIT: Bonus - generic rule to process ANY event for a given topic & source
def ruleSpotifyEvent = new SimpleRule() {
@Override
Object execute(Action module, Map<String, ?> inputs) {
try {
logger.debug("Received: " + inputs.get("event").toString() + " - type: " + ((ItemEvent)inputs.get("event")).type)
def itemName = ((ItemEvent)inputs.get("event")).getItemName()
def ohEventType = ((ItemEvent)inputs.get("event")).type
if(ohEventType == "ItemStateEvent") {
ItemStateEvent ohEvent = (ItemStateEvent)inputs.get("event")
// ohEvent.itemState holds the new state ....
... do fancy stuff here ...
}
}
ruleSpotifyEvent.name = "genericEvent"
ruleSpotifyEvent.setTriggers([TriggerBuilder.create()
.withLabel("genericEvent")
.withId("genericEvent")
.withTypeUID("core.GenericEventTrigger")
.withConfiguration(
new Configuration([
eventTopic: "openhab/items/*",
eventSource: "spotify",
eventTypes: "ItemStateEvent,ItemCommandEvent"]))
.build()]
)
automationManager.addRule(ruleSpotifyEvent)