Why does this Expression mis-calculate at 8:30 AM?


#1

I’m trying to set up my own circadian daylight piston; I know they exist but I’d like to create one for my own purposes. The theory is this… I have variables for Time1, Time2, Time3, and corresponding Level1/2/3 and Temperature1/2/3. When time($now) is Time1, set @Level to Level1 and @Temperature to Temperature1.

Then I want Level1 to slowly transition to Level2 by Time2. Same thing for Temperature2.

I’ve come up with an expression that has a few parts. First, it’ll determine how much time their is between Time1 and Time2 (e.g. 5 hours), and how much time has passed $now since Time1 (e.g. 1 hour). It’ll divide those 2 values to determine how far along that time span we are $now (e.g. 20%, or 0.2). Then it’ll take the difference between Level2 (e.g. 100) and Level1 (e.g. 90; difference is 10) and multiply that number by how far along (e.g. 0.2 * 10 = 2) and add that number to Level1.

Logically, this makes sense to me… Figure what percentage of that time span has passed, add that proportion of the difference in Levels to Level1. When it runs every 5 minutes, it’ll slowly transition from Level1 to Level2.

Expression is:
($now-Time1)/(Time1-Time2) * (Level2-Level1) + Level1

It works great for certain times, but it spazzes out at others and I can’t figure it out. In my example piston (see attached) testtime takes the place of $now (once it’s actually working). If I make testtime 8:00 AM, works great. If I make it 9:00 AM, works great. If I make it 8:30 AM it gives me a spazzy number. When I plug the expression into the expression editor, each of the “segments” make sense;
1/5 * 10 + 90
= 92

but the entire expression gives me a wrong number of “1.33”

I’ve tried this dozens of ways and I just can’t figure out why it won’t consistently work.

For troubleshooting purposes, my local $sunrise is 7:51 AM and $sunset is 4:40 PM.

Any ideas?


#2

What data types are the variables you are using? Make them long


#3

I was using “decimal” for my levels and “integer” for my temperatures. Just changed those both to “long” but now it gives me a different wrong answer.


#4

formatDuration returns a string - you are trying to subtract it from a Temperature2 - that just doesn’t make sense. You can’t use formatDuration in algebraic algorithms. If you want to round down to minutes, use (time % 60000) or a floor(time / 60000) function or even (time \ 60000) I believe that’s an integer division. Or use round(time / 60000) for rounding, or ceil(time / 60000), but certainly not formatDuration.


#5

Ok, so what is the best way to figure out how far along $now is relative to the total time between Time1 and Time2?


#6

Sorry, can you please rephrase that? You’re trying to compare an absolute time ($now) to a time delta (time2-time1), not sure I follow


#8

What I’m trying to do is figure out how far along the span between time1 and time2 is at the time it’s evaluated. I have an “every 5 minutes” timer running that will evaluate what percentage of time has passed between 2 different times. For example, if time1 is 8:00 AM and time2 is 11:00 AM, if the timer executes at 9:00 AM (e.g. $now is 9:00) then I want to return a value of 0.33 (1 hour into a 3 hour time span).


#9

Ok, so with the assumption that

Time1 < $now < Time2

Your formula is simply

($now - Time1) / (Time2 - Time1)

You can use conditionals to make it smarter

$now < Time1 ? 0 : ($now > Time2 ? 1 : ($now - Time1) / (Time2 - Time1))

That would return 0 if $now hasn’t yet entered the interval or 1 if $now has already passed it, effectively pinning the result between 0 and 1 inclusive. This still assumes Time1 < Time2


#10

Also be aware that $now is a datetime. You need to use datetime variables if your time interval passes midnights. A datetime holds the number of milliseconds since midnight of Jan 1st, 1970, whereas a time variable holds the number of milliseconds since last midnight. Therefore, time variables reset to 0 at midnight and your interval may no longer be contiguous if Time1 and Time2 are on different days.


#11

I took some tips from the responses and incorporated them into an idea I had for a simpler execution. I’m using a parabolic equation y=-4.3(x-0.5)^2+1 which will give me an inverted parabola starting at (0,0), max height of 1 and ending at (0,1). This should give me a nice arc throughout the day. As “percentage of the day span” moves from 0 to 1, the temperature/level arcs toward the max, then back down to the min value. I’ve plugged in some test numbers and I think it should work fine.

The expression is:

MinTemp+(-4.3*(sqr(((time($now))-(time(Start)))/((time(End))-(time(Start)))-0.5))+1)*(MaxTemp-MinTemp)

… which appears to work fine so far.

The piston is attached here:


#12

Please read my previous reply about using time variables (the time() function returns a time data type) - you will run into trouble if Start and End are on different days. You may want to use datetime()


#13

I did see that, but I hadn’t realized it! In this particular case I’m not too upset since it’s for a daylight circadian pattern and the start/end will always be within the same day.


#14

Did you get to the bottom of the issue? I’m about to program the lighting and heating based on a circadian pattern and wondered if you have any tips you’d be happy to share?

Thanks

Dicky