How to get a sine wave around sunrise/sunset?

I’m trying to get a sine wave shaped input to regulate the temperature for my formicarium. Sun elevation looks nice, but its maxima are variable…

So if any math wizard here can get me a formula that takes sunrise and sunset as inputs and outputs a point on a sine wave for the current time with sunrise and sunset at 0, and the midpoints at 1/-1, it would be great.

I’d also take a way to get the sun’s elevation as a percentage of that day’s maximum, but I guess that’d be harder and I don’t actually need the value to realistically follow the sun, I just want it to be smooth and follow daylight.

Obviously, it’s not really a sine wave if the day and night are different lengths. This seems to work with rudimentary testing:

{% set sr = state_attr('sun.sun','next_rising')|as_timestamp - today_at()|as_timestamp %}
{% set sr = sr - [86400, 0][sr < 86400] %}
{% set ss = state_attr('sun.sun','next_setting')|as_timestamp - today_at()|as_timestamp %}
{% set ss = ss - [86400, 0][ss < 86400] %}
{% set n = now()|as_timestamp - today_at()|as_timestamp %}
{% set n = n + [0, 86400][n < sr] %}
{% set dl = ss - sr if ss > sr else 86400 - (sr - ss) %}
{{ ((-1, sin(pi * ((n - ss) / (dl - 86400), (n - sr) / dl)[ss > n > sr]), 1)|sort)[1] }}

sr and ss are the seconds into the day of the next sunrise and sunset times (assumes today’s times are the same as tomorrow’s); n is the current time as seconds into the day. dl is the length of daytime in seconds.

Final line can be broken down into:

(-1, x, 1)|sort[1]

is a clever trick to limit the value to between -1 and 1. Given the slight differences each day, each waveform will either clip to the limit for a few minutes or not quite reach the limit.

Then x is:

sin(pi * y)

where y is the proportion into day or night duration that the current time is, with a sign change for night-time.

There’s probably a much easier way to do it with elevation if you’re prepared to store max and min elevations each day, and scale to those again assuming the day-to-day change is negligible.

1 Like

Thank you very much!

Looks good at first glance, I’ll let it run for a day and report back with the graph it generates.

I like that sort trick. Way less convoluted than [-1, [1, x]|max]|min

Edit: And I just noticed [list][bool as number] for ?:. Nifty.

1 Like

Mostly little tricks I picked up from here (usually Taras) or the Code Golf scene.

[output if false, output if true][boolean] (or the same with a (tuple)) is a favourite of mine. Perhaps not as readable as iif at first glance.

It’s looking good so far: let’s see how it fares through the night… (% just as a placeholder unit to allow a graph)


It’ll probably jump in odd ways on daylight saving days, if you’re somewhere that has those. I’m sure the ants will cope, though.

Yes, we have that. And yes, they won’t mind. It’s just weather to them. They’d be fine with a constant temperature, too, and many people have it that way because dumb thermostats can only do that, but why not give them a bit of a more natural thermal profile if I can?

Looks plausible here, too. (I made it into a percentage just for display purposes.)

1 Like


Not an absolutely perfect transition around zero, but I’m happy with that:


Yes, this works for me, too. Big thanks again!

When that value gets converted into a target temperature, that transition will be invisible, and after it has gone through the thermostat and converted into a binary heater on/off pattern even more, and when it becomes a measured temperature… :wink:

Here is how that looks with my old sun.elevation-based math (you can see how it’s nowhere near the maxima):

I just changed the input to the new sine wave, that’s the jump at the end. (Note1: I’m clamping the value around the peak to get a longer “noon”. Note2: On a cold day like today, the little 6W heater does its own clamping, it only manages 4° over ambient. That’ll get better once I can place it under the arena, but for now it’s at the side as the ants haven’t yet moved into their nest and contact heat from below isn’t good for their brood.)

I’ll post an updated graph tomorrow. Unless I messed up the temp conversion too much :wink:

Yes, this works fine. Here’s a 24-hour run.

(I’m still tweaking the width of the clamped times for Arena, and Nest doesn’t have a real heater installed as it’s not yet in use. Nest also has way more thermal mass (damp substrate vs air).)

1 Like