From time to time, I get a crazy idea of changing something small in my automation setup. Usually, an idea like that drags me into a rabbit hole, I didn’t know it had existed. Whatever I do nowadays, I always look at it with an angle: “Would that make an interesting tutorial?” and that angle has turned a simple “Is it night time yet?” query, into a 200 line long coding challenge. I hope someone will appreciate it the fact I made a tool to check which part of the world needs a flashlight.
The “bigtimer” node is great… until it isn’t
I have been using the “bigtimer” node for a long time. As my NodeRED flows grow, adding the same nodes each time around becomes a burden and a complication that you have to deal with. Having a global set of values that I can use is the best coding practice, than reconfiguring a “bigtimer” node each time you want to deal with a timer or reconfigure a group of the devices that are not connected to the same node.
I wanted to have a global variable, which would store information about the time of the day: day/night. On the surface, it’s a simple idea. When you actually approach the problem (and the fact that you would like to share the idea with other people in different parts of the world) things get a little bit harder.
If you are here to rip the fruit of my work, scroll down to the bottom and download the flow. You can also buy me a coffee while you at it.
Creating a time keeping alternative
To calculate the day|night I decide to convert the current time to seconds from 1970 (Unix time) and compare the numeric values against the sunset and sunrise values. To be able to do so, I need sunset and sunrise values. I can obtain this using a free sunrise-sunset.org/api. While personally, I can use UTC (the only time zone they offer the values for) I get tangled into the daylight saving, and you my dear reader won’t even come close to that time zone according to my Google Analytics.
Exploring the rabbit hole
- tell you if it’s night or day
- tell you the sunrise and sunset time
- tell you the day length
- provide you with astronomical, nautical, civil dusk and dawn times
- use these values to create timers
- all that good stuff in your local time!
Step one: changing coords into a time zone.
Geographical coordinates are used to determine the sunset/sunrise times and the time zone. I need that information otherwise, you are stuck forever with UTC. I didn’t want to hardcode the details to make the flow accessible to everyone. There is a free time zone API that can be used to work out your time zone and the time offset between your home and UTC.
A set of coordinates (saved globally as I will use it each time to query the sun info) is used to establish the home time zone with an HTTP GET request. This request will give me a time zone needed to calculate the offset.
Step two: from X to UTC in plenty of seconds
To calculate the local time, I need an offset. There is a very clever way of calculating the time difference. If I change all values into seconds, I can simply add and subtract the values. Since I already know the “home” zone – I can start the second HTTP GET query, to calculate the offset in seconds between your “home” zone and UTC. I will store that offset as a global variable.
Step three: rise and shine
I know the coordinates. I know the offset. I can make the last HTTP GET request to get the sun info in UTC. This request will contain all the sun information. Before I can store it as global values, I have to recalculate the times.
I mentioned before, that the easiest way would be to change the values to seconds, add the offset and change the values back to a human-readable format. This applies to all values apart from the “day length” as that value is given in seconds already.
Step one too many: the easy way
And then I found getTimezoneOffset(); You can forget steps 1 and 2. It’s fair to say I learned a thing or two along the way. This method basically takes the local timezone and calculates the offset between the local timezone and the UTC. Which just ruined half of the tutorial! Oh well… now you have to examples to download. The returned value is in minutes, so there will be a little bit of math to do.
Where are the timers?
The time-related methods can be used to extract the years, months, days, hours, minutes etc. Each value can be compared with a condition using a relatively simple IF statement. You have seen me doing this with “is it night time yet” where I would compare the current time against the sunrise|sunset conditions. The same applies when comparing other time values.
The "bigtimer" will have its uses, and my method is not a replacement for that useful node. If you want to check the value of the time against the existing condition inside the function node, now you have the toolset to do so.
Sometimes, it's all about the journey. I spend an evening working on the flow. The last method was something I came accross after I finished it. I don't feel bad about it as I like puzzles, but at the same time I would save myself a bit of time and move to the next project earlier. They say knowledge is power. If you read the whole article, you have the power too! Join the discussion on Reddit about this post!