In the broad sense, an automation is an algorithm that takes data from some Items and derives the state of others: e.g., controlling ventilation by CO₂, lights by time of day, heating by temperature, etc.
After building a number of such automations, I realized what I don’t like:
- Automations ignore manual changes to the controlled element. You might control lighting by time of day, but there will be moments when you want to turn it off at night or on during the day manually.
- Sometimes you need to quickly toggle specific automations off and back on—not all of them at once. For example, you have an automation regulating ventilation, but guests arrive and they feel a draft. You also want a quick overview of what is currently enabled/disabled.
- A disabled automation ≠ no automation. I decided the system should bring me back into the automated state once the situation changes.
- Most automation algorithms look template-like: when something changes or on an interval, change something else, possibly checking a short retrospective window (the last N minutes).
In one “factory” system (unfortunately I don’t recall which) I saw a very simple, clear, and elegant approach: a three-state switch for each automation — enabled / disabled / disabled for a duration. A manual change of the controlled element simply disables the corresponding automation for a set time, after which it automatically returns to the working state. You can also fully enable or disable an automation manually.
For a while I built such a switch for each automation by hand; it was tedious and a lot of boilerplate. Then I created a dedicated JS library, “automator”, and battle-tested it. I now consider it stable and useful beyond my own setup - openhab-automator on npm.
How it works (example from the docs)
Say you want to automate turning on the kitchen light if there’s motion and it’s dark.
The example below (described in words) demonstrates most features, many of which are optional:
const automator = require('openhab-automator');
// Create an automator for the kitchen light
const m = automator.for('Kitchen_Light')
.label('Kitchen Light — Auto', 'Kitchen')
// Custom options (minutes -> label)
.options({
'2': '2 min OFF',
'120': '2 h OFF'
}, '2') // default manual OFF duration (minutes)
.onActivate(() => {
console.log('Kitchen auto: ON');
})
.onDisable(() => {
console.log('Kitchen auto: OFF');
});
// Logic: turn on if there is motion and it’s dark; turn off if no motion
m.handler(function (event) {
const motion = this.Kitchen_Motion;
const lux = this.Kitchen_Lux_average_5m; // persistence average over 5 minutes
if (motion && lux < 50) return true; // ON for Switch
if (!motion) return false; // OFF
})
.dependsOf('Kitchen_Motion', 'Kitchen_Lux') // declare dependencies
.debounce(15) // soft debounce 15 s
.interval(60); // check every minute
-
If there is motion and the average illuminance over the last 5 minutes is < 50 lx, turn the light on; if illuminance rises above the threshold, turn it off. (As an example only—yes, the logic is simplistic.)
-
The automation is evaluated on lighting changes, motion changes, or every 60 seconds (because we use a 5-minute average), with a soft debounce of 15 s so it won’t “flicker”.
-
If you manually toggle the kitchen light, the automation pauses for 2 minutes.
-
I often use the automation’s
onActivate/onDisableevents to send messages to the logs and/or to our home Telegram notifications.