ESPRESSO machine warmup timer in openHAB (ECMAScript rule + custom widget + push notification)
Hi folks,
I wanted a simple “espresso warmup” UI for my Lelit Mara X already controlled via a z-wave smart plug in openHAB:
-
Toggle machine ON/OFF from MainUI / Android app
-
When switched ON: start a reverse warmup timer (24:00 → 00:00)
-
Display the remaining time as mm:ss
-
Send a push notification when the machine is ready
-
Allow switching OFF anytime (plan changes)
This post documents the working solution using a JS Scripting rule (ECMAScript 262 Edition 11) plus a custom MainUI widget.
Motivation
The Mara X needs ~24 minutes to reach stable temperature. I already had the machine on a plug in openHAB, but I wanted a “one glance” widget that:
-
shows ON/OFF,
-
shows the countdown live,
-
displays power consumption to check function
-
alerts me when it’s ready.
Solution path (what worked reliably)
-
Create a
Numberitem that stores remaining seconds (e.g. 1440 for 24 minutes). -
Create a JS rule that:
-
starts/restarts the countdown whenever the espresso plug is switched ON
-
cancels/reset when switched OFF
-
decrements every second
-
sends a notification when reaching 0 from counting
-
-
Create a custom widget that:
-
shows a toggle for the plug
-
formats the seconds item as
mm:ss -
shows power consumption (Watts) in a second line
-
Note: for the Z-Wave switch channel link I kept the default profile (no Script Profile). The automation belongs in the rule, not the channel link.
Required Items
-
Your existing plug switch item (example):
ZP55PCPower_Switch -
A “remaining seconds” Number item:
Lelit_RS -
An optional status switch:
Lelit_WarmupActive
(Items can be created in the UI: Settings → Items → Add Item.)
Required Rule (ECMAScript 262 Edition 11)
Trigger
- When Item state changed →
ZP55PCPower_Switch
(Works great for ON/OFF. If you want “restart timer even if ON is pressed again while already ON”, use “Item received command”.)
Script (paste into the Rule action)
This version:
-
starts at 24 minutes
-
counts down
Lelit_RS -
aborts instantly if you switch OFF
-
sends push notification when reaching READY from counting
// Lelit Warmup – ECMAScript 262 Edition 11
// Trigger: ZP55PCPower_Switch toggled (state changed or command received)
const PLUG_ITEM = "ZP55PCPower_Switch";
const REMAIN_ITEM = "Lelit_RS";
const ACTIVE_ITEM = "Lelit_WarmupActive";
const WARMUP_SECONDS = 24 * 60; // 24 minutes
const NOTIFY_RECIPIENT = "ohuser@mydomain.com";
const TIMER_KEY = "Lelit_WarmupInterval";
const NOTIFIED_KEY = "Lelit_Notified";
function stopTimer(resetRemaining) {
const t = cache.private.get(TIMER_KEY);
if (t) {
clearInterval(t);
cache.private.remove(TIMER_KEY);
}
items.getItem(ACTIVE_ITEM).postUpdate("OFF");
cache.private.put(NOTIFIED_KEY, "0");
if (resetRemaining) items.getItem(REMAIN_ITEM).postUpdate(0);
}
function startTimer() {
// restart every time we start
stopTimer(false);
items.getItem(REMAIN_ITEM).postUpdate(WARMUP_SECONDS);
items.getItem(ACTIVE_ITEM).postUpdate("ON");
cache.private.put(NOTIFIED_KEY, "0");
const tick = () => {
// If user switched off anytime -> abort
if (String(items.getItem(PLUG_ITEM).state) !== "ON") {
stopTimer(true);
return;
}
let remaining = parseInt(String(items.getItem(REMAIN_ITEM).state), 10);
if (!Number.isFinite(remaining)) remaining = 0;
const prev = remaining;
remaining = Math.max(0, remaining - 1);
items.getItem(REMAIN_ITEM).postUpdate(remaining);
if (remaining === 0) {
// Notify only if we reached 0 from counting (>0) and not yet notified
const notified = String(cache.private.get(NOTIFIED_KEY) || "0") === "1";
if (prev > 0 && !notified) {
actions.NotificationAction.sendNotification(
NOTIFY_RECIPIENT,
"Lelit Mara X ist aufgeheizt ☕"
);
cache.private.put(NOTIFIED_KEY, "1");
}
stopTimer(false);
}
};
cache.private.put(TIMER_KEY, setInterval(tick, 1000));
}
// ---- event handling (supports different trigger payloads) ----
(function (event) {
// if run manually, just (re)start timer
if (typeof event === "undefined" || !event) {
startTimer();
return;
}
// only act on plug item
if (event.itemName && event.itemName !== PLUG_ITEM) return;
// different triggers expose different fields
let newState =
(event.newState !== undefined ? event.newState : undefined) ??
(event.itemState !== undefined ? event.itemState : undefined) ??
(event.receivedState !== undefined ? event.receivedState : undefined) ??
(event.receivedCommand !== undefined ? event.receivedCommand : undefined);
newState = String(newState);
if (newState === "ON") {
startTimer(); // restart countdown every ON trigger
} else if (newState === "OFF") {
stopTimer(true); // cancel anytime + reset
}
})(event);
Push notification note
This uses openHAB Cloud notifications (sendNotification). It will deliver to the openHAB app for the user account matching NOTIFY_RECIPIENT (myopenHAB email).
Custom Widget (toggle + remaining time + watts)
Create a personal widget in MainUI:
-
Developer Tools → Widgets → Create Widget
-
UID:
lelit-warmup -
Paste YAML:
uid: lelit-warmup
component: f7-card
config:
title: "Lelit Mara X"
style:
padding: 12px
slots:
default:
- component: f7-row
config:
class:
- align-items-start
slots:
default:
# Left: toggle
- component: f7-col
config:
style:
display: flex
align-items: center
height: 100%
slots:
default:
- component: oh-toggle
config:
item: ZP55PCPower_Switch
# Right: two-line status
- component: f7-col
config:
class:
- text-align-right
slots:
default:
# Line 1: remaining time in mm:ss (OFF/READY fallback)
- component: Label
config:
style:
font-size: 22px
font-family: monospace
line-height: 1.1
text: "=(items['ZP55PCPower_Switch'].state !== 'ON') ? 'OFF' : ((Number.parseInt(items['Lelit_RS'].state,10) > 0) ? (('0' + Math.floor(Number.parseInt(items['Lelit_RS'].state,10)/60)).slice(-2) + ':' + ('0' + (Number.parseInt(items['Lelit_RS'].state,10)%60)).slice(-2)) : 'READY')"
# Line 2: power consumption (Watts)
- component: Label
config:
style:
font-size: 14px
opacity: 0.8
margin-top: 4px
text: "=((items['ZP55PCPower_Electricmeterwatts'].state === 'NULL' || items['ZP55PCPower_Electricmeterwatts'].state === 'UNDEF') ? '-- W' : (items['ZP55PCPower_Electricmeterwatts'].state + ' W'))"
If your watt item already includes the unit (e.g. 123 W as a QuantityType), simply remove the extra ' W' in the widget line.
Result
-
Toggle ON → timer starts at 24:00 and counts down
-
Toggle OFF at any time → timer cancels/reset
-
When reaching 0 from counting → push notification “ready”
-
Widget shows remaining time
mm:ss+ current power draw
Hope this helps anyone building a coffee dashboard in openHAB ![]()