Home Home Automation A Timer in NodeRED

A Timer in NodeRED

An offline timer in IoT is priceless

You can laugh all you want at me, but I’m excited! Why? It’s Halloween and timers have been haunting me for way too long! I finally cracked it! I’d like to show you how to make infinite timers in NodeRED which can be set via Dashboard. My timer in NodeRED not only works offline, but it’s modular! What a time to be alive!

Why so serious? It’s just a timer in NodeRED!

Before I decided to play Dr Strange of JavaScript and reinvent the wheel in a function node, I was like everyone else using “bigtimer” node made by Peter Scargill. I’m in no way discouraging you from using that node, but each method has its own pros and cons.

I needed a simple Dashboard timer which I can add to any IoT device, so I could set the schedules via NodeRED Dashboard rather than hardcode the values in NodeRED.

I present you with a Timer in NodeRED:

  • Modular (as a subflow)
  • Unlimited timers per device
  • Supports “days of the week”
  • works offline
  • Dashboard interface
  • One button reset

Unlike my other flows, this one is very easy to add to your creations. This timer in NodeRED can be deployed as a single subflow configurable via NodeRED 1.0 environmental variables.

To configure the subflow, you have to provide the timer iteration (each timer should have its own number like: 1|2|…n) and values for payload on start and stop (string).

Apart from the Dashboard (obviously?), you will need the Schedex node so head to palette manager and install:


What’s the catch?

Nothing is perfect, and timer in NodeRED has annoyances too! The way the Dashboard works makes it impossible to simply import the subflow and hope that the widget will be added in the right place.

All elements are configured correctly, but the Dashboard will try to fill in spaces on your web interface by shifting the elements up. The result may look tragic, but everything will work fine.

To fix the layout, you will need to add a couple of spacers. There is no rule how big the spacers should be, as all this depends on your layout in the Dashboard, just make sure the elements don’t shift up.

If you want to have multiple timers on the same page, you are better off duplicating the subflow manually, then setting the values of the environmental variables yourself.

How does it work?

I tried to make this flow as simple as possible. I used the groundwork laid in articles about calculating time in Tasker (underlying maths is the same, plus Tasker supports JavaScript).

function calcTime(hh){
     var hours = ("0"+Math.floor((hh%86400)/3600)).slice(-2);
     var minutes = ("0"+Math.floor((hh%3600)/60)).slice(-2);
     return hours + ":" + minutes;

“Pick time” Dashboard element generates time in milliseconds since midnight. To set a valid timer, I will need the start time and the end time. These values are converted to seconds (division by 1000) and I can use the clever JavaScript to add leading zeros and format it to HH:MM format needed for the Schedex node.

When the time is set in the picker, a function node saves it as a flow variable and sets the button labels to provide the visual feedback.

Function Node: Set T2 On/OFF
var z = flow.get("Timer1");

//if timer on is set
if(msg.topic === "Ton"){
    flow.set("timer"+z+"_on", msg.payload);
    msg.color = "red";
    msg.topic = "Press";
    return [msg, null];

//if timer off is set
if(msg.topic === "Toff"){
    flow.set("timer"+z+"_off", msg.payload);
    msg.color = "red";
    msg.topic = "Press";
    return [null, msg];

// reboot detected
if(msg.topic === "reboot"){
    msg.color = "grey";
    msg.topic = "Select Time";
    return [msg, msg];

I wanted this visual feedback to be clear, so not only I change the colour and labels of the buttons, but I included a text label showing that the timer had been set.

Function Node: On Button Press
var z = flow.get("Timer1");
var pon = flow.get("Payload"+z+"_on");
var poff = flow.get("Payload"+z+"_off");

function calcTime(hh){
    var hours = ("0"+Math.floor((hh%86400)/3600)).slice(-2);
    var minutes = ("0"+Math.floor((hh%3600)/60)).slice(-2);
    return hours + ":" + minutes;

var time = null;
var timerlabel = "Timer "+ z;

// when button on is pressed
if(msg.topic === "buttonON"){
    var t1  = flow.get("timer"+z+"_on")/1000;
    time = calcTime(t1);
    flow.set("T"+z+"on", time);
    //send to text element
    //var msg1 = {payload: "SET", topic: timerlabel, color: "green"};
    //send to schedex
    var msg1 = {payload: {ontime: "ontime " + time,
                          onpayload: pon,
                          suspended: false},
                topic: "SET",
                color:   "green"};
    return [msg1,null];
// when button off is pressed
if(msg.topic === "buttonOFF"){
    var t2 = flow.get("timer"+z+"_off")/1000;
    time = calcTime(t2);
    flow.set("T"+z+"off", time);
    //send to text element
    //var msg3 = {payload: "SET", topic: timerlabel, color: "green"};
    //send to schedex
    var msg2 = {payload: {offtime: "offtime " + time,
                          offpayload: poff,
                          suspended: false},
                topic: "SET",
                color:   "green"};
    return [null,msg2];

return msg;

My work on the timer has been interrupted once because of unexpected Raspberry Pi shutdown. Inspired by this failure, I have promptly added a couple of inject nodes with Started! which triggers on reboot.

To use this, make sure your context|flow|global variables are saved by NodeRED – you can learn how here.

Function Node: Apply stored values
var z = flow.get("Timer1");
var pon = flow.get("Payload"+z+"_on");
var poff = flow.get("Payload"+z+"_off");

// restore days
var mon = flow.get("Monday"+z);
var tue = flow.get("Tuesday"+z);
var wed = flow.get("Wednesday"+z);
var thu = flow.get("Thursday"+z);
var fri = flow.get("Friday"+z);
var sat = flow.get("Saturday"+z);
var sun = flow.get("Sunday"+z);

//restore timers
var timeON = flow.get("T"+z+"on");
var timeOFF = flow.get("T"+z+"off");
var timerlabel = "Timer "+ z;

msg.payload = { "ontime": "ontime " + timeON, "onpayload": pon,
                "offtime": "offtime " + timeOFF, "offpayload": poff,
                "mon": mon,
                "tue": tue,
                "wed": wed,
                "thu": thu,
                "fri": fri,
                "sat": sat,
                "sun": sun

return msg;

Now your timer can survive reboots, saving time ON|OFF and the days of the week.

Lastly, schedex node supports days of the week, so there is no reason not to drop in 7 switches and name it accordingly! Unfortunately, implementation is a bit clunky, so I don’t know an easy way of combining it in a single function node, but it’s workable:

var z = flow.get("Timer1");
 var x = msg.payload;
 flow.set("Monday"+z, x);
 msg.payload = {mon: x};
 return msg;


I promised the node to be simple to deploy and use. To use it in your NodeRED flow, deploy the subflow and edit the environmental variables. The node will create the following Flow Variables for you to use:

  • Timer[ID]_on – time on in seconds from midnight
  • Timer[ID]_off – time off in seconds from midnight
  • T[ID]on – HH:MM time on
  • T[ID]off – HH:MM time off
Timer #

You will need to provide the timer number (as int 0,1,2,3 etc keep this easy to track). Each flow can have unlimited timers, providing each comes with a unique number. Practically, the limit will come from hardware specification like heap memory available to NodeRED.

ON|OFF Payload

You can also assign a custom payload. It’s an afterthought really, as I quickly realised that you don’t have to litter your Flow with another switch node. The payload is configured as a “string“, so if you want something more specific like bool or a number, you will need to convert it yourself.


Free timers for everyone! This timer has been made specifically for IKEA Smart Socket write up (soon), but I will be incorporating this also into my Nest alike smart heating (check it out, it works with old thermostats!) and probably other systems that use schedules. I may consider adding reboot behaviour so you could decide how the node reacts if power is restored (sending missed schedules vs ignoring it). Let me know what would you use if for and what other functions would be useful in this Reddit thread.

Project Download

Download project files here. Bear in mind that Patreon supporters have early access to project files and videos.


Nothing says "Thank you" better than keeping my coffee jar topped up!


Support me on Patreon and get an early access to tutorial files and videos.


Bitcoin (BTC)

Use this QR to keep me caffeinated in style with crypto-currency

Smart Ideas with

Automate your space in with these ecosystems and integrate it with other automation services

Learn NodeRED

NodeRED for beginners: 1. Why do you need a NodeRED server?

To server or not to server? That's a very silly question!

Best Automation Projects

ESP8266 WIFI lights under $5

Your Sonoff device can't do this!

Free wireless doorbell (Amazon Dash button hack)

The most terrifying situation I can imagine* is missing a parcel

New Amazon Dash Buttons

You can teach new buttons old tricks!

ESP8266 ceiling light – demo

Testing the ESP8266 as a WIFI light controller

Try Tasker and Raspberry Pi for your home automation needs!

Raspberry Pi can help you with your Tasker profiles

Smart Home

Army of robots: SwitchBot Curtain

An army of SwitchBot Curtains - adorable CurtainBots to open and close practically any curtains!

Zemismart Roller Shade Driver

Frustrated with UK's roller measurements I reached out for Zemismart Roller Shade Driver

Most affordable smart lightbulbs: Sonoff B02 & B05

ITEAD just dropped a range of very affordable smart Sonoff lightbulbs

Creepy Alexa for Halloween

Turning Amazon Echo into a Creepy Alexa monster for Halloween

How to make Sonoff ZB Mini and ZigBee2MQTT work together

It's time to make Sonoff ZB Mini and ZigBee2MQTT work together!