Control Outdoor lightning - with newbie questions

So I start this new thread instead of pollute my Feture Request thread ([url=http://forum.micasaverde.com/index.php/topic,111066.0.html]http://forum.micasaverde.com/index.php/topic,111066.0.html[/url]) with this newbie questions.
The Feature request was hasty fixed by awesome rigpapa

What I want is to control my outdoor lightning as follows.
Start Scene outdoor light ON

  • every day 5 min before nautical dusk
  • every morning at 05.45am if it still dark outside (between dusk and dawn)

Start Scene outdoor light OFF

  • every night at 00.00
  • every morning 5min after nautical dawn

Here comes my questions/thoughts so far
Can I use only one reactor sensor? Is this what the un-trip scene thing is for? sensor untrips = lights off, sensor trips = lights on?

What I understand reactor works even if Vera happens to reboot at a time an event should start. Is that why I can’t set a specific time like lamps on exactly 05.45am? It needs a time frame to work within?

I don’t really understand the answer rigpapa gave in my other thread

[quote=“rigpapa, post:6, topic:200035”][quote=“Andr, post:4, topic:200035”]One question of lesser importance (I think)
In one group the I have two conditions,

  • between dusk - dawn
  • Time is between 05:45-05:50, here I basically just want to start my outdoor lightning scene if it is dark outside and time is 05:45, but I couldn’t really see how to just set at specific time?[/quote]

Group #1:
Sunrise/sunset condition: after dusk <— this condition is true from dusk to midnight
Time condition: after 17:45 <— this condition is true from 17:45 to midnight

Group #2:
Sunrise/sunset condition: before dawn <— this condition is true from midnight to dawn

The first group’s conditions will trip the ReactorSensor and trigger your “lights on” scene at the later of dusk or 5:45pm (it’s “AND” within a group, so both conditions need to be met). These conditions automatically reset at midnight. To prevent that reset from untripping the ReactorSensor and running your “lights off” scene too early, the second group’s single condition becomes true at midnight and stays true until dawn. So at midnight the first group goes false, but the second group goes true in the same instant, so the ReactorSensor stays tripped. At dawn, that lone condition in the second group goes false, and at that point both groups are false, so your ReactorSensor untrips and runs the “lights off” scene.[/quote]
Why is “before dawn” in a separate group?

[quote=“Don Phillips, post:7, topic:200035”]Using PLEG, and I suspect it would work with Reactor, I read weather conditions and offset the sunrise/sunset by 15 minutes for overcast and 30 minutes for precipitation.
…[/quote]
This is a great idea!
How do I get Vera/Reactor to interact with weather data?
I know I can see weather on dashboard, but i have never seen some way to interact on it.

[quote=“Andr, post:1, topic:200039”]So I start this new thread instead of pollute my Feture Request thread ([url=http://forum.micasaverde.com/index.php/topic,111066.0.html]http://forum.micasaverde.com/index.php/topic,111066.0.html[/url]) with this newbie questions.
The Feature request was hasty fixed by awesome rigpapa

What I want is to control my outdoor lightning as follows.
Start Scene outdoor light ON

  • every day 5 min before nautical dusk
  • every morning at 05.45am if it still dark outside (between dusk and dawn)

Start Scene outdoor light OFF

  • every night at 00.00
  • every morning 5min after nautical dawn

Here comes my questions/thoughts so far
Can I use only one reactor sensor? Is this what the un-trip scene thing is for? sensor untrips = lights off, sensor trips = lights on?[/quote]

That’s correct. A single Reactor sensor, and it can turn on the lights at the correct time when it trips, and turn them back off later when it untrips. The logic above keeps the ReactorSensor tripped throughout the “active” period–the period you want the lights on.

What I understand reactor works even if Vera happens to reboot at a time an event should start. Is that why I can't set a specific time like lamps on exactly 05.45am? It needs a time frame to work within?

That’s basically right. An “after xx:xx” time condition will run exactly at xx:xx if the Vera is up and running, so it is effectively an “at xx:xx” in that sense. But because it’s really a span test, it will also become true if the Vera is unplugged at exactly xx:xx and later gets plugged in and boots up. I suppose I could add an “exactly at” condition, but it seems redundant.

I don't really understand the answer [b]rigpapa[/b] gave in my other thread [quote="rigpapa, post:6, topic:200035"][quote="Andr, post:4, topic:200035"]One question of lesser importance (I think) In one group the I have two conditions, - between dusk - dawn - Time is between 05:45-05:50, here I basically just want to start my outdoor lightning scene if it is dark outside and time is 05:45, but I couldn't really see how to just set at specific time?[/quote]

Group #1:
Sunrise/sunset condition: after dusk <— this condition is true from dusk to midnight
Time condition: after 17:45 <— this condition is true from 17:45 to midnight

Group #2:
Sunrise/sunset condition: before dawn <— this condition is true from midnight to dawn

The first group’s conditions will trip the ReactorSensor and trigger your “lights on” scene at the later of dusk or 5:45pm (it’s “AND” within a group, so both conditions need to be met). These conditions automatically reset at midnight. To prevent that reset from untripping the ReactorSensor and running your “lights off” scene too early, the second group’s single condition becomes true at midnight and stays true until dawn. So at midnight the first group goes false, but the second group goes true in the same instant, so the ReactorSensor stays tripped. At dawn, that lone condition in the second group goes false, and at that point both groups are false, so your ReactorSensor untrips and runs the “lights off” scene.[/quote]
Why is “before dawn” in a separate group?

An “after” or “before” condition with time only (no month, day, year date) resets at midnight. It’s really like one would normally think about time, I think. If you want to do something after 4:00 in the afternoon, then a person thinks like this: (a) 8:00am is too early–it’s not time yet; (b) 2:00pm is too early–it’s not time yet; (c) 4:15pm–I should be doing it! (d) 9:00pm–I still should be doing it; (e) 1:00am–it’s a new day, and so it’s not time yet. Reactor thinks this way as well.

Put another way, and “after xx:xx” condition is a synonym for “between xx:xx and midnight”, while a “before xx:xx” condition is a synonym for “between midnight and xx:xx”.

Now look at the logic I suggested. The first logic group has two conditions. For a logic group to be TRUE, all the conditions in it have to be true (that’s the “AND” logic of a group). The first condition in the group is our sun test–is it now after dusk? That condition will be true from dusk to midnight. The second condition in our test, is it after 17:45, will be true from 17:45 to midnight. So by "AND"ing them together, the group is only true when both are true, and this has the effect of being true only when it is both after disk and after 17:45, so therefore true at the later of the two time events, logically. With the ReactorSensor set up with a “trip scene” to turn on the lights, the lights will be turned on at that time.

So, the first group will turn on the lights at the right time. The problem, though, is that if we do nothing else, both conditions will go false at midnight; this will reset the group to false, and the ReactorSensor itself will then see no group is true, so it will untrip. If you have set the “untrip scene” to turn off your lights, your lights will go out at midnight. That’s too early, so we need to fix that with some additional logic.

The second group in the ReactorSensor has the single condition “before dawn”. Using the rules above, it means that this condition will be true between midnight and whatever time dawn is calculated to be. So at midnight, this condition becomes true. Because it is the only condition in the group, the group becomes true as well (all group conditions are true), so the ReactorSensor wants to be tripped.

There are two groups in this ReactorSensor. That means the sensor’s overall state will be the “OR” of the two groups–if either group 1 OR group 2 is true, the sensor will be true/tripped. So let’s just step through time to see what happens. For this example, I’ll assume that dusk comes later than 17:45, but it doesn’t really matter…

Event 1: 17:45 rolls around and Reactor determines that the second condition of group 1 is now true. The first condition (after dusk) has not yet been met, however, so group 1 is still false. Group 2 is also false. Reactor knows there’s nothing more to do on this ReactorSensor until either dusk or dawn, and dusk is coming sooner, so it schedules its next update for that time.

Event 2: At the calculated dusk time, Reactor determines it’s now dusk, so the first condition of group 1 now goes true; both conditions are now true, so Reactor sees that its overall state is untripped, so it transitions to tripped state and runs the “tripped scene”. The lights are now on. Job done, Reactor knows there’s nothing more to do until either dawn or midnight, so it schedules itself for an update at midnight and gets some rest.

Event 3: It’s midnight. Reactor wakes up and evaluates the group 1 conditions, and determines both of them to be false, so group 1’s state becomes false. It then evaluates the single group 2 condition (“before dawn”) and determines it to be true, so group 2’s state becomes true. Reactor then sees that a group is true (group 2), so it needs to be tripped. But it’s already tripped, and it only reacts to changes in state, so it doesn’t do anything more (it doesn’t re-set tripped state or re-run the “tripped scene”). The lights are still on, because event 2 turned them on. Reactor determines that the sensor’s next event will take place at dawn, so it goes to sleep until then.

Event 4: Dawn! Reactor wakes up, and now determines that group 2’s condition is false, so group 2 goes false. Now, there are no true groups, so Reactor now wants its overall state to be untripped, but it knows it’s in tripped state, so it transitions to untripped, and runs the “untripped scene”, which turns off the lights. Job done. It now determines that the next time event will be at 17:45 that day, so it goes to sleep until then (and at that time, it starts over at event 1).

So, the first group takes care of the period before midnight. The second group takes care of the period after midnight. The net effect is that the ReactorSensor is tripped from the later of dusk or 17:45 to dawn–it’s tripped throughout the period we want the lights ON. So then, it’s just a matter of setting up the scenes to turn the lights on when the ReactorSensor trips, and off when it untrips. These scenes can run by Reactor directly (recommended, use the Activities tab), or by Vera’s scene triggers (using the ReactorSensor’s tripped state as the trigger).

Also note that at Event 3 an important feature of Reactor is at play. Reactor reacts to changes in state. In this event, one group goes false, and the other goes true, but the result of the OR logic between the two groups still produces the same result. That is, before event 3, the logic is TRUE (group 1) OR FALSE (group 2) ==> TRUE (overall target state). At event 3, it shifts to FALSE (group1) OR TRUE (group 2) ==> TRUE (overall). The overall state doesn’t change, even though the groups have changed. But because the overall state hasn’t changed, Reactor doesn’t do anything more–it doesn’t re-trip or run any scenes. I like to say that Reactor reacts to “edges” not “states.” The same is true at every condition: if you have a single temperature condition in a ReactorSensor that is true when an outdoor temperature sensor reports a temperature below 10C, and the sensor reports 9C, the condition is true, and if it was previously false, Reactor responds to it (trips). Then, if the temperature sensor later reports that it’s now cooled further to 8C, the condition is still true, but that’s not a change from its previous state, so it doesn’t perform any actions in this case. You can see the value change on the condition in the status tab, but that doesn’t change the condition’s result state, or the group’s result state, or the ReactorSensor’s tripped state.

Another detail to note: Reactor schedules its re-evaluations of time conditions (including sunrise/sunset) intelligently. If you use an “after 17:45” condition, for example, it does not re-evaluate that condition every minute leading up to it, or every minute after, to see if the condition is met or not. It determines the time “edges” from the condition values and operator, and schedules the update for the soonest next possible event. So if it’s currently 2:00pm and Reactor is looking for your “after 17:45” condition to be true, it won’t evaluate that condition until exactly 17:45. It’s asleep until that point. This is one of the reasons Reactor is light and fast on the older Vera hardware, a big requirement of mine.

Let’s rewind a moment…

The whole thing got more complicated because you introduced the idea that you wanted the lights on at the later of 17:45 and dusk. If you just wanted the lights on from dusk to dawn, a single condition would do the job:

  • sunrise/sunset - between dusk and dawn

That’s all that’s needed. But, because you also needed a specific time for which the lights should not come on any earlier, we had to split the condition logic up. Why can’t we just add the time to the condition as you originally tried? Let’s see… if we add “after 17:45” to this condition, our one and only condition group now becomes:

  • sunrise/sunset - between dusk and dawn
  • time/date - after 17:45

If we run this in time (again assuming dusk is later than 17:45), the progress of events is: (1) 17:45 arrives, so condition 2 is true, but condition 1 is false, so the group is false, no action; (2) dusk arrives, so condition 2 is now true, condition 1 is already true, so everything in the group is true and Reactor trips the ReactorSensor and runs the “lights on” scene… so far so good, right? well… (3) midnight rolls around and now condition 2 goes FALSE, so the group goes false… and the ReactorSensor untrips and runs the “lights off” scene. At midnight. Too early. So the purpose of splitting the “between” into separate “before” and “after” conditions in two groups was to address this fault.

Another way to fix it would be to use a “between” condition on the time. Let’s say you want the lights on no earlier than 17:45, but also no later than 7:00 in the morning. You can make your conditions like this:

  • sunrise/sunset - between dusk and dawn
  • time/date - between 17:45 and 07:00

That “between” time condition is a game-changer. That second condition will remain true across midnight, and go false after 7am. The two conditions are now working together, and the lights will stay on between (a) the later of 17:45 and dusk, and (b) the earlier of dawn and 07:00. So that’s a different way of solving your original problem, but by adding a condition you didn’t originally make (lights on no later than 7am). If you didn’t want to restrict the morning period, you could also make that a ridiculously out of range time (a time later than any dawn in your location), like 11am, so that the dawn test is really the only controlling condition for the morning.

[quote="Don Phillips, post:7, topic:200035"]Using PLEG, and I suspect it would work with Reactor, I read weather conditions and offset the sunrise/sunset by 15 minutes for overcast and 30 minutes for precipitation. ...[/quote] This is a great idea! How do I get Vera/Reactor to interact with weather data? I know I can see weather on dashboard, but i have never seen some way to interact on it.

You need a weather plugin to get the data. Reactor can then see the plugin device’s data and do its logic with it. There are several solutions out there. I myself use SiteSensor and just query a weather API directly, but that’s my plugin, so of course that’s my solution.

Super, I will need a moment to wrap my brain around this ;D
Will try to adjust my settings when I am home again tonight.

A minor misunderstanding, don’t think it matters much for the logic you described.
I live in Sweden were we closing in on the winters dark age with just a few hours of daylight.
So I want light On every day when its getting dark. Then Off again at midnight (the wild animals doesn’t need my light)
Then On again at early morning 05:45/5.45am (we doesn’t use am/pm here so I guess I mislead you when I didn’t clarified this) at that time it more or less completely dark outside for half the year. Then Off again at dawn.

Super, I will need a moment to wrap my brain around this ;D
Will try to adjust my settings when I am home again tonight.

A minor misunderstanding, don’t think it matters much for the logic you described.
I live in Sweden were we closing in on the winters dark age with just a few hours of daylight.
So I want light On every day when its getting dark. Then Off again at midnight (the wild animals doesn’t need my light)
Then On again at early morning 05:45/5.45am (we doesn’t use am/pm here so I guess I mislead you when I didn’t clarified this) at that time it more or less completely dark outside for half the year. Then Off again at dawn.[/quote]

Ah… my misunderstanding… so that’s actually pretty simple embellishment on the previous:

Group 1:

  • sunrise/sunset - after dusk
  • time/date - after 17:45

Group 2:

  • sunrise/sunset - before dawn
    * time/date - after 05:45 <---- new

The first group, as before, will be true after the later of dusk and 17:45. At midnight, it will reset to false (lights off).

The modified second group now includes an “after” time condition, which changes the behavior so that rather than becoming true at midnight, it can’t become true until 5:45am. The “before this” and “after that” combination is effectively a “between”, so it will only be true from 5:45am to dawn, then false again (lights off).

(the wild animals doesn't need my light)

The deer here in Georgia seem to appreciate the overnight lights I give them while they feast on the buffet that they apparently think my front garden beds are.

So now I think I’m starting to get a hang of it :slight_smile:
At least it seems to work the way I want. If it helps anyone I attach a picture of this sensor. (I did some minor adjustments to have the light on a bit longer at weekend nights.

After reading a bit more and trying around a bit I must say I am REALLY impressed how you designed and planned this plug-in.

Some questions and thoughts has popped in my brain.

  • I uploaded the lua-file you linked to, does that affect the plug-in auto update thing thru Vera market?
  • Is there a way to get/read a status or value of a device service? Preferably in Condition screen. What I think is that a noob like me doesn’t always know what value i want to react to, so it would be helpful to see what value there is right now. For example is a Sonos play status reported with 1 or 0, PLAY, ON etc.
  • For me it doesn’t help to reset my sensor when I Test different times, but if I click save in Condition it resets immediately with that time I selected.
  • About weather it seems like there is no working plugin anymore since Underground killed its free api. I will take a look at your Sitsensor thing and see if I can make something out of it.
    If it helps anyone I found out that the Swedish meteorologic institute offers a free api. I don’t know if they have forecast info outside scandinavian area, but the api-stuff is in english if it is interesting to someone. I don’t have a clue what to with it :o
    Link here: [url=http://opendata.smhi.se/apidocs/metfcst/index.html]http://opendata.smhi.se/apidocs/metfcst/index.html[/url]

[quote=“rigpapa, post:4, topic:200039”][quote=“Andr, post:3, topic:200039”]

(the wild animals doesn’t need my light)

The deer here in Georgia seem to appreciate the overnight lights I give them while they feast on the buffet that they apparently think my front garden beds are.[/quote][/quote]

Yeah, I can almost stand the deers, but the moose I f*k hate! That big marauder destroys everything!
Next plan for reactor sensor, activate a small minefield if outdoor lights are off and it is dark outside ;D

[quote=“Andr, post:5, topic:200039”]So now I think I’m starting to get a hang of it :slight_smile:
At least it seems to work the way I want. If it helps anyone I attach a picture of this sensor. (I did some minor adjustments to have the light on a bit longer at weekend nights.[/quote]
Yes, coming along! Well done!

Some questions and thoughts has popped in my brain. - I uploaded the lua-file you linked to, does that affect the plug-in auto update thing thru Vera market?

The plugins should continue to update. I just posted a new version to the Plugin Marketplace over the weekend, so that code and the stable branch on Github are currently in sync/identical. You should show version 1.8 in the footer of the config and test tabs.

Is there a way to get/read a status or value of a device service? Preferably in Condition screen. What I think is that a noob like me doesn't always know what value i want to react to, so it would be helpful to see what value there is right now. For example is a Sonos play status reported with 1 or 0, PLAY, ON etc.

That’s a great idea. I’ll add that to the feature list.

For me it doesn't help to reset my sensor when I Test different times, but if I click save in Condition it resets immediately with that time I selected.

Huh. It was the forced reset on save that got broken a couple of revisions ago, but the Restart button has always worked (I think–nobody else has reported problems, and it always works for me). Because it runs as a Vera job, it may take a moment before Vera decides to start running it, if it’s also busy with other jobs (e.g. a long-running Z-wave command).

About weather it seems like there is no working plugin anymore since Underground killed its free api. I will take a look at your Sitsensor thing and see if I can make something out of it. If it helps anyone I found out that the Swedish meteorologic institute offers a free api. I don't know if they have forecast info outside scandinavian area, but the api-stuff is in english if it is interesting to someone. I don't have a clue what to with it :o Link here: [url=http://opendata.smhi.se/apidocs/metfcst/index.html]http://opendata.smhi.se/apidocs/metfcst/index.html[/url]

I’ll take a look. If I come up with a quick recipe, I’ll post it.

OK. Not too bad, but it is a fairly lengthy response. Here’s a SiteSensor recipe:

For others reading: the API used below is geographically limited and may not work outside Sweden.

Request URL: [tt]https://opendata-download-metfcst.smhi.se/api/category/pmp3g/version/2/geotype/point/lon/16.158/lat/58.5812/data.json[/tt]
(change the lat/lon as needed for your location)

Request Headers: none

Request Interval: 3600 (recommended, since the forecasts are hourly)

Response type: [tt]JSON data[/tt]

Trigger type: [tt]URL unreachable…[/tt]

Trip Expression: none

Value Expression 1: [tt]first( select( response.timeSeries[1].parameters, “name”, “t” ).values )[/tt]

Value Expression 2: [tt]first( select( response.timeSeries[1].parameters, “name”, “r” ).values )[/tt]

Value Expression 3: [tt]first( select( response.timeSeries[1].parameters, “name”, “wd” ).values )[/tt]

Value Expression 4: [tt]first( select( response.timeSeries[1].parameters, “name”, “ws” ).values )[/tt]

This API returns forecasts over the next ten days–a lot of data. We are only using the first forecast ([tt]response.timeSeries[1][/tt]), which is for the current hour. The forecast data is in an array called “parameters”, hence that reference. Since the “parameters” data is an array of objects, we use the “select()” function to find the object in the array where the value of the “name” key is the parameter name we’re interested in: “t” for temperature, “r” for humidity, “ws” for wind speed, “wd” for wind direction. All of the types available are documented here. So the result of the select() function is the parameter object we want in the first time series (first forecast). The value of the parameter object is given by the API as an array of one element (not sure why, never saw any responses with more than one element in this array), so we use the first() function to just fetch the first (and in this case only) element from that array, and we have our value.

The results are placed in the SiteSensor state variables (in service [tt]urn:toggledbits-com:serviceId:SiteSensor1[/tt]) [tt]Value1[/tt] (for temperature), [tt]Value2[/tt] (for humidity), [tt]Value3[/tt] (for wind direction), and [tt]Value4[/tt] (for wind speed). You can access/respond to the variables from Reactor, Vera scene device triggers, Lua (e.g.[tt]luup.variable_get( “urn:toggledbits-com:serviceId:SiteSensor1”, “Value1”, sensorDeviceNum )[/tt]) or other facilities that watch device state variables.

I’ll continue to this thread since my need is the same as Andr. I have outdoor lights which I want to switch on at the morning and switch off when there’s enough sunlight, and then switch on again at the evening when sun goes down and then off at midnight.

With some experimentation and looking statistics the suitable ON times for my usage are: 6:15 to dawn+30min and dusk-30min to midnight. This schedule is easy to enter to Reactor and all works well.

However, I noticed that since civil dusk and dawn times here vary a lot, at some point of the year ON times will get very short, just minutes and then seconds before time conditions will not trigger at all. Short flashing of lights is not wanted so some more conditions are needed.

I solved the problem by calculating ON times by expressions and then adding condition that ON time needs to be at least 10min. This requires accessing sundata which contains needed civil dusk and dawn times. Here is the logic:

YardLightControl (#44) Version 2.1548342922 01/24/19 17:15:22 Message/status: Not tripped Variable/expressions myDawnDuration=mysundata[3]-dateadd(mysundata[2],0,15,6)+1800 (last "8172") myDuskDuration=dateadd(mysundata[2],0,0,0,1)-mysundata[8]+1800 (last "26629") mysundata=split(getstate("Reactor","urn:toggledbits-com:serviceId:Reactor","sundata"),"%D+") (last "table: 0x1383310") Group #1 <grp1685b2fb9dd> false as of 00:00:00 =f (sun) after civdusk-30, [false/false as of 00:00:00/00:00:00; 1548484260 at 08:31:00] <cond1685b2fb9de> =T (service) YardLightControl (44) urn:toggledbits-com:serviceId:ReactorValues/myDuskDuration >= 600 Group #2 <grp1687ab79a9f> false as of 08:31:00 =f (sun) before civdawn+30, [false/false as of 08:31:00/08:31:00; 1548484260 at 08:31:00] <cond1687ab79aa1> =T (trange) after ,,,6,15,,,,, [true/true as of 06:15:00/06:15:00; 1548484260 at 08:31:00] <cond1687ab853e8> =T (service) YardLightControl (44) urn:toggledbits-com:serviceId:ReactorValues/myDawnDuration >= 600 Trip Actions Device 41 (Driveway_lights) action urn:upnp-org:serviceId:SwitchPower1/SetTarget( newTargetValue=1 ) Untrip Actions Device 41 (Driveway_lights) action urn:upnp-org:serviceId:SwitchPower1/SetTarget( newTargetValue=0 )

Accessing sundata like this does not feel very comfortable, the code will break if sundata structure is changed. Is there better way to access? Or could be added to future releases? Or is there some simpler ways altogether to achieve the presented control?

Another request would be that if I calculate times in expressions, could these be used in conditions the same way Sunrise/Sunset casn be used now? (i.e. before, after, etc…)

The lights did not come on this morning. The reason is version 2.2. Since I am quite new with Vera didn’t know that apps will autoupdate by default. A good reminder that if you have important tasks running you should not let system update automatically but rather test first and then take into use.

Issues found with version 2.2:
-The “stamp” data in sundata I think should be date. Now it contains 2019029 instead of 20190129 i.e. part of the month is missing?

-If variable is type object, it cannot be used in other expressions. Strings and numbers work fine.
For example if variable is defined by expression:

split(getstate("Reactor","urn:toggledbits-com:serviceId:Reactor","sundata"),"%D+")
it cannot be used. But if defined:

getstate("Reactor","urn:toggledbits-com:serviceId:Reactor","sundata") can be used. In version 2.1 both expressions could be used.

Other minor issue was that sundata has now additional data so my index based solution got wrong values. So taking all the found issues into account, a new solution was needed not using “stamp” or object type variable. Here is the new version which works also in 2.2:

YardLightControl (#44) Version 19012.1548751044 01/29/19 10:37:24 Message/status: Not tripped Variable/expressions myDawnDuration=tonumber(sub(sdata,find(sdata,"civdawn")+10,find(sdata,"civdawn")+19)) - dateadd(time("00:00:00"),0,15,6) + 1800 (last "7838") myDuskDuration=dateadd(time("00:00:00"),0,0,0,1) - tonumber(sub(sdata,find(sdata,"civdusk")+10,find(sdata,"civdusk")+19)) + 1800 (last "26218") sdata=getstate("Reactor","urn:toggledbits-com:serviceId:Reactor","sundata") (last "{ \"stamp\": 2019029, \"civdawn\": 1548741338, \"nautdawn\": 1548738233, \"sunset\": 1548771850, \"nautdusk\": 1548777888, \"latitude\": 60.2052, \"astrodusk\": 1548780837, \"longitude\": 24.6522, \"civdusk\": 1548774782, \"astrodawn\": 1548735284, \"sunrise\": 1548744270 }") Group #1 <grp1685b2fb9dd> false as of 00:00:00 =f (sun) after civdusk-30, [false/false as of 00:00:00/00:00:00; 1548750991 => 1548751048 at 10:37:28] <cond1685b2fb9de> =T (service) YardLightControl (44) urn:toggledbits-com:serviceId:ReactorValues/myDuskDuration >= 600 Group #2 <grp1687ab79a9f> false as of 07:20:52 =f (sun) before civdawn+30, [false/false as of 08:25:00/08:25:00; 1548750991 => 1548751048 at 10:37:28] <cond1687ab79aa1> =T (trange) after ,,,6,15,,,,, [true/true as of 06:15:00/06:15:00; 1548750991 => 1548751048 at 10:37:28] <cond1687ab853e8> =T (service) YardLightControl (44) urn:toggledbits-com:serviceId:ReactorValues/myDawnDuration >= 600 Trip Actions Device 41 (Driveway_lights) action urn:upnp-org:serviceId:SwitchPower1/SetTarget( newTargetValue=1 ) Untrip Actions Device 41 (Driveway_lights) action urn:upnp-org:serviceId:SwitchPower1/SetTarget( newTargetValue=0 )

[quote=“Vpow, post:9, topic:200039”]The lights did not come on this morning. The reason is version 2.2. Since I am quite new with Vera didn’t know that apps will autoupdate by default. A good reminder that if you have important tasks running you should not let system update automatically but rather test first and then take into use.

Issues found with version 2.2:
-The “stamp” data in sundata I think should be date. Now it contains 2019029 instead of 20190129 i.e. part of the month is missing?[/quote]

The stamp in sundata, and in fact the entirety of sundata, are internal values that I don’t guarantee across versions. Use at your own risk. But for the sake of clarity, the new stamp is a Julian form date; it is correct as shown.

-If variable is type object, it cannot be used in other expressions. Strings and numbers work fine.

For example if variable is defined by expression:

split(getstate("Reactor","urn:toggledbits-com:serviceId:Reactor","sundata"),"%D+")
it cannot be used.

The fact that any data type LuaXP returned that wasn’t a string or number worked at all in previous versions was a lucky accident, and in fact, they didn’t really work entirely, as their real value was only available during the same condition evaluation cycle–the value could not be stored on a Luup state variable, which can only store strings. So the only reason it worked for you was that you were basically using it like a local variable (which you could also do explicitly, but that’s another subject).

In my effort to establish how these should work and make them work “properly” for the long term, I’ve added two new functions: [tt]stringify()[/tt] and [tt]unstringify()[/tt]. Your expression should now be rewritten as:

stringify( split(getstate("Reactor","urn:toggledbits-com:serviceId:Reactor","sundata"),"%D+") )

This will ensure that the stored representation of the non-primitive data type (an object/array in this case) will work for Luup state variables (which can only store strings). Any expression result that returns a non-primitive type (i.e. not a string, number or boolean) must be [tt]stringify()[/tt]'d.

To undo that and use the stored data:

unstringify( variablename )

But that’s not quite all for your particular case…

Other minor issue was that sundata has now additional data so my index based solution got wrong values.

sundata is not an indexed array. It is actually a Lua table of key/value pairs, and the order of keys in the table is not guaranteed, so using it as an indexed array is going to fail eventually, and will do so in a non-deterministic way that you can never fix. Even if I never change the contents of sundata, the order is determined by the underlying Lua implementation and can change at any time for any reason, even just over a reboot. The fact that it hasn’t changed on you before this is just a happy accident, once again.

What you really need to do is pull the data out by its key. You will very reliably always get what you want that way. And, this is where the new functions I have added come into play and fulfill their destiny exactly as planned (mad scientist hand-wringing going on over here):

unstringify( getstate( "Reactor", "urn:toggledbits-com:serviceId:Reactor", "sundata" ) ).civdawn

The above example will pull the time value for civil dawn. The [tt]unstringify()[/tt] function handles JSON data, so it’s perfect for parsing sundata. If you are going to do this several times to get several values, I recommend you store the result of [tt]getstate()[/tt] in a separate variable, and then use that interim variable as the [tt]unstringify()[/tt] argument (you seem to have done this already with the sdata variable–good show).

Now, hold on…

[code]YardLightControl (#44) Version 19012.1548751044 01/29/19 10:37:24 Message/status: Not tripped Variable/expressions myDawnDuration=tonumber(sub(sdata,find(sdata,"civdawn")+10,find(sdata,"civdawn")+19)) - dateadd(time("00:00:00"),0,15,6) + 1800 (last "7838") myDuskDuration=dateadd(time("00:00:00"),0,0,0,1) - tonumber(sub(sdata,find(sdata,"civdusk")+10,find(sdata,"civdusk")+19)) + 1800 (last "26218") sdata=getstate("Reactor","urn:toggledbits-com:serviceId:Reactor","sundata") (last "{ \"stamp\": 2019029, \"civdawn\": 1548741338, \"nautdawn\": 1548738233, \"sunset\": 1548771850, \"nautdusk\": 1548777888, \"latitude\": 60.2052, \"astrodusk\": 1548780837, \"longitude\": 24.6522, \"civdusk\": 1548774782, \"astrodawn\": 1548735284, \"sunrise\": 1548744270 }") Group #1 false as of 00:00:00 =f (sun) after civdusk-30, [false/false as of 00:00:00/00:00:00; 1548750991 => 1548751048 at 10:37:28] =T (service) YardLightControl (44) urn:toggledbits-com:serviceId:ReactorValues/myDuskDuration >= 600 Group #2 false as of 07:20:52 =f (sun) before civdawn+30, [false/false as of 08:25:00/08:25:00; 1548750991 => 1548751048 at 10:37:28] =T (trange) after ,,,6,15,,,,, [true/true as of 06:15:00/06:15:00; 1548750991 => 1548751048 at 10:37:28] =T (service) YardLightControl (44) urn:toggledbits-com:serviceId:ReactorValues/myDawnDuration >= 600 Trip Actions Device 41 (Driveway_lights) action urn:upnp-org:serviceId:SwitchPower1/SetTarget( newTargetValue=1 ) Untrip Actions Device 41 (Driveway_lights) action urn:upnp-org:serviceId:SwitchPower1/SetTarget( newTargetValue=0 ) [/code]

So, what are you doing with all these gyrations with myDuskDuration and myDawnDuration? I’m not following your logic here. What does all this do for you?

My use case here is to control lights in two occasions during the day. From 06:15 to civil dawn+30min and from civil dusk-30min until midnight. In order to prevent too short light control sequences I calculate myDawnDuration and myDuskDuration and added conditions to check whether those are more than 10 minutes.

Now that I am writing this I came up with another possible solution which does not use expressions at all. By adjusting the off control times by 10 mins and adding 10 min delay to untrip action should do it:

YardLightControl2 (#45) tripped Version 19012.1548779321 01/29/19 18:28:41 Message/status: Disabled Group #1 <grp1689a6eb162> true as of 18:26:59 =T (sun) after civdusk-30, [true/true as of 18:26:59/18:26:59; 1548779266 => 1548779325 at 18:28:45] <cond1689a6eb163> =T (trange) before ,,,23,50,,,,, [true/true as of 18:26:59/18:26:59; 1548779266 => 1548779325 at 18:28:45] <cond1689a6efde3> Group #2 <grp1689a6f51d2> false as of 18:26:59 =T (trange) after ,,,6,15,,,,, [true/true as of 18:27:46/18:27:46; 1548779266 => 1548779325 at 18:28:45] <cond1689a6f51d5> =f (sun) before civdawn+20, [false/false as of 18:27:46/18:27:46; 1548779266 => 1548779325 at 18:28:45] <cond1689a6fa230> Trip Actions Device 41 (Driveway_lights) action urn:upnp-org:serviceId:SwitchPower1/SetTarget( newTargetValue=1 ) Untrip Actions Delay 600 inline Device 41 (Driveway_lights) action urn:upnp-org:serviceId:SwitchPower1/SetTarget( newTargetValue=0 )

Don’t know which one is more robust solution for power breaks… I guess latter one will not switch on lights if control is restarted after untrip. But this does not matter for this use case, light control is no way critical.

I think the exercise with expressions was still usable. If sundata can be accessed in future versions reliably, it can be useful. How about the suggestion of possibility of adding variables to time conditions? (e.g. I calculate variable X by some expression, then want to make condition “before X” etc.)

THAT makes sense.

Now that I am writing this I came up with another possible solution which does not use expressions at all. By adjusting the off control times by 10 mins and adding 10 min delay to untrip action should do it:
YardLightControl2 (#45) tripped
    Version 19012.1548779321 01/29/19 18:28:41
    Message/status: Disabled
    Group #1 <grp1689a6eb162> true as of 18:26:59
        =T (sun) after civdusk-30, [true/true as of 18:26:59/18:26:59; 1548779266 => 1548779325 at 18:28:45] <cond1689a6eb163>
        =T (trange) before ,,,23,50,,,,, [true/true as of 18:26:59/18:26:59; 1548779266 => 1548779325 at 18:28:45] <cond1689a6efde3>
    Group #2 <grp1689a6f51d2> false as of 18:26:59
        =T (trange) after ,,,6,15,,,,, [true/true as of 18:27:46/18:27:46; 1548779266 => 1548779325 at 18:28:45] <cond1689a6f51d5>
        =f (sun) before civdawn+20, [false/false as of 18:27:46/18:27:46; 1548779266 => 1548779325 at 18:28:45] <cond1689a6fa230>
    Trip Actions
        Device 41 (Driveway_lights) action urn:upnp-org:serviceId:SwitchPower1/SetTarget( newTargetValue=1 )
    Untrip Actions
        Delay 600 inline
        Device 41 (Driveway_lights) action urn:upnp-org:serviceId:SwitchPower1/SetTarget( newTargetValue=0 )

Clean and simple. I like it.

Don't know which one is more robust solution for power breaks.. I guess latter one will not switch on lights if control is restarted after untrip. But this does not matter for this use case, light control is no way critical.

Not quite sure what you mean here. If that’s a typo and you meant “I guess latter one will not switch OFF lights if control is restarted after untrip”… it will. Reactor activities survive reboots/restarts/power failures and will continue as close to schedule as possible once restored.

I think the exercise with expressions was still usable. If sundata can be accessed in future versions reliably, it can be useful. How about the suggestion of possibility of adding variables to time conditions? (e.g. I calculate variable X by some expression, then want to make condition "before X" etc.)

That is more about user interface than logic. That’s been the case with Reactor for some time now–keeping a clean, understandable UI is a challenge. Juggling all the various options and making sure the rights things are enabled and disabled at the right time builds up a lot of code. In this case, there’s the matter of the date/time conditions operating in three modes: Y/M/D.H:M, M/D.H:M, and H:M. If we chose a variable, we’d have to also provide a way say “ignore the year” (to get M/D H:M mode) or “ignore the date” (to get H:M mode).

But back up a step. You can put your condition logic entirely in an expression, and then just have the condition look at the expression result as a boolean. Here’s a trivial example:

    Version 19012.1548784606 01/29/19 12:56:46
    Message/status: Tripped
    Variable/expressions
        currentmonth=tonumber(strftime("%m")) (last "1")
        poolstarthour=if( currentmonth > 4 and currentmonth < 11, 7, 10 ) (last "10")
        runpool=tonumber(strftime("%H")) >= poolstarthour (last "1")
    Group #1 <grp16521749eeb> true as of 12:56:46
        =T (service) Expression Reactor (24) urn:toggledbits-com:serviceId:ReactorValues/runpool istrue 1 [true/true as of 12:56:46/12:56:46; 0 => 1 at 12:56:46] <cond166265b1436>
    Trip Actions (none)
    Untrip Actions (none)
    Events```

The idea is to start pool equipment at 7am from May through October, and 10am otherwise. The expression is broken up just to make it easier to look at. The [tt]currentmonth[/tt] simply gets the current month of the year as a number (now 1). The [tt]poolstarthour[/tt] uses an [tt]if()[/tt] to figure out the hour at which to start the equipment based on the month. The [tt]runpool[/tt] variable then is a boolean that is true if the current hour is greater or equal to the seasonal start hour we computed. Group 1 then just checks [tt]runpool[/tt].

Thanks for the example! Didn’t realize before that such advanced conditions can be created by expressions.

So far Reactor looks very promising addition to Vera giving quite easy way to create wanted controls. I might consider donating :slight_smile:

Found something from the Delay action.

-If the delay is at the very beginning of untrip actions and the delay is of type “from this point”, it does not work; untrip actions will never(?) finish. Delay type “from start of actions” works as expected; after conditions untrip delay waits x seconds and then performs other untrip actions.

-The user interface keeps showing “from this point” for the delay regardless what is selected. Logic summary shows either inline or start correctly according what was selected.

[quote=“Vpow, post:14, topic:200039”]Found something from the Delay action.

-If the delay is at the very beginning of untrip actions and the delay is of type “from this point”, it does not work; untrip actions will never(?) finish. Delay type “from start of actions” works as expected; after conditions untrip delay waits x seconds and then performs other untrip actions.

-The user interface keeps showing “from this point” for the delay regardless what is selected. Logic summary shows either inline or start correctly according what was selected.[/quote]

Superb. Found both of those. Fixes are posted to the “hotfix” branch. Read this post for more information and what files to update (and how) to get the fixes.

My dusk-to-dawn light control was working fine, until recently. I noticed that lights were on even they were not supposed to be. After some investigation I found the reason; start of the dusk had gone way beoynd midnight. So when I had condition “switch on lights after civdusk offset -30min” this condition become true in early hours and lights were on most of the day.

This leads to a interesting question, is there a bug in Reactor dusk time (and other times…) calculation? I suppose the times are re-evaluated at midnight and should give the times for coming 24h day. Now it happens that dusk time goes to beoynd 24h limit and time is for the next day. I’ll leave this for rigpapa to check. In addition it is possible that there are actually two dusks per 24h; one just after midnight and one just before :slight_smile: Maybe the new dusk time should be calculated as soon as time point for current dusk has been reached…

Meanwhile I needed to fix my light control. I could not find a way to do it in “Conditions” only. I added an expression “time() > (unstringify(getstate(“Reactor”,“urn:toggledbits-com:serviceId:Reactor”,“sundata”)).civdusk - 1800)” which is then checked true or false in conditions combined with rule that lights can be on only before midnight. This seems to work for now.

Please post a Logic Summary (Tools tab)

INSTRUCTIONS: When pasting this report into the Vera Community forums, please include ALL lines below this one. The next and last lines will ensure proper formatting and must not be removed!
*************************************************** REACTOR LOGIC SUMMARY REPORT ***************************************************
   Version: 3.2 config 301 cdata 19082 ui 19143 pluginDevice 42
    System: Vera version 1.7.4452 on Sercomm NA301; loadtime 1560447539; systemReady 1560447551; Lua 5.1
Local time: 2019-06-17T15:11:39+0300; DST=1
House mode: plugin 1; system 1; tracking off
  Sun data: { "stamp": 2019168, "civdawn": 1560726213, "nautdawn": null, "sunset": 1560800977, "nautdusk": null, "latitude": 60.2052, "astrodusk": null, "longitude": 24.6522, "civdusk": 1560807653, "astrodawn": null, "sunrise": 1560732890 }
  Geofence: not running
====================================================================================================================================
YardLightControl2 (#45)
    Version 19082.34 06/14/19 18:08:01
    Message/status: Not tripped
    Variable/expressions
       1: dusklight                time() > (unstringify(getstate("Reactor","urn:toggledbits-com:serviceId:Reactor","sundata")).civdusk - 1800) [last false(boolean)] (exported)
    Condition group "YardLightControl2" (AND) false as of 06-14.17:26:54 <root>
      &-F-group "light_ON" (OR) false as of 02:23:00 <grp1689a6eb162>
      |     |-F-service YardLightControl2 (45) urn:toggledbits-com:serviceId:ReactorValues/dusklight istrue  [1560524674 => 0 at 06-14.18:06:47; F/F as of 06-14.18:06:47/06-14.18:06:47] <cond1689a6eb163>
      |     |-F-sun before civdawn+20, [1560727380 => 1560741300 at 06:15:00; F/F as of 02:23:00/02:23:00] <cond1689a6fa230>
      &-T-group "light_OFF" (AND) TRUE as of 06:15:00 <grp1689a6f51d2>
      |     &-T-trange bet ,,,6,15,,,,23,50 [1560727380 => 1560741300 at 06:15:00; T/T as of 06:15:00/06:15:00] <cond1689a6f51d5>
    Activity root.false
        Delay 600 start
        Device 41 (Driveway_lights) action urn:upnp-org:serviceId:SwitchPower1/SetTarget( newTargetValue="0" )
    Activity root.true
        Device 41 (Driveway_lights) action urn:upnp-org:serviceId:SwitchPower1/SetTarget( newTargetValue="1" )
    Events
        06/15/19 00:00:00 condchange: newState=true, cond=cond1689a6fa230, oldState=false
        06/15/19 00:00:00 evalchange: newState=true, cond=cond1689a6fa230, oldState=false
        06/15/19 00:00:00 condchange: newState=true, cond=grp1689a6eb162, oldState=false
        06/15/19 00:00:00 evalchange: newState=true, cond=grp1689a6eb162, oldState=false
        06/15/19 02:26:00 condchange: newState=false, cond=cond1689a6fa230, oldState=true
        06/15/19 02:26:00 evalchange: newState=false, cond=cond1689a6fa230, oldState=true
        06/15/19 02:26:00 condchange: newState=false, cond=grp1689a6eb162, oldState=true
        06/15/19 02:26:00 evalchange: newState=false, cond=grp1689a6eb162, oldState=true
        06/15/19 06:15:00 condchange: newState=true, cond=cond1689a6f51d5, oldState=false
        06/15/19 06:15:00 evalchange: newState=true, cond=cond1689a6f51d5, oldState=false
        06/15/19 06:15:00 condchange: newState=true, cond=grp1689a6f51d2, oldState=false
        06/15/19 06:15:00 evalchange: newState=true, cond=grp1689a6f51d2, oldState=false
        06/15/19 10:04:13 action: action=Restart
        06/15/19 10:04:13 start: 
        06/15/19 10:05:20 action: action=Restart
        06/15/19 10:05:20 start: 
        06/15/19 23:50:00 condchange: newState=false, cond=cond1689a6f51d5, oldState=true
        06/15/19 23:50:00 evalchange: newState=false, cond=cond1689a6f51d5, oldState=true
        06/15/19 23:50:00 condchange: newState=false, cond=grp1689a6f51d2, oldState=true
        06/15/19 23:50:00 evalchange: newState=false, cond=grp1689a6f51d2, oldState=true
        06/16/19 00:00:00 devicewatch: name=Reactor, var=sundata, device=42
        06/16/19 00:00:00 condchange: newState=true, cond=cond1689a6fa230, oldState=false
        06/16/19 00:00:00 evalchange: newState=true, cond=cond1689a6fa230, oldState=false
        06/16/19 00:00:00 condchange: newState=true, cond=grp1689a6eb162, oldState=false
        06/16/19 00:00:00 evalchange: newState=true, cond=grp1689a6eb162, oldState=false
        06/16/19 02:25:00 condchange: newState=false, cond=cond1689a6fa230, oldState=true
        06/16/19 02:25:00 evalchange: newState=false, cond=cond1689a6fa230, oldState=true
        06/16/19 02:25:00 condchange: newState=false, cond=grp1689a6eb162, oldState=true
        06/16/19 02:25:00 evalchange: newState=false, cond=grp1689a6eb162, oldState=true
        06/16/19 06:15:00 condchange: newState=true, cond=cond1689a6f51d5, oldState=false
        06/16/19 06:15:00 evalchange: newState=true, cond=cond1689a6f51d5, oldState=false
        06/16/19 06:15:00 condchange: newState=true, cond=grp1689a6f51d2, oldState=false
        06/16/19 06:15:00 evalchange: newState=true, cond=grp1689a6f51d2, oldState=false
        06/16/19 23:50:00 condchange: newState=false, cond=cond1689a6f51d5, oldState=true
        06/16/19 23:50:00 evalchange: newState=false, cond=cond1689a6f51d5, oldState=true
        06/16/19 23:50:00 condchange: newState=false, cond=grp1689a6f51d2, oldState=true
        06/16/19 23:50:00 evalchange: newState=false, cond=grp1689a6f51d2, oldState=true
        06/17/19 00:00:00 devicewatch: name=Reactor, var=sundata, device=42
        06/17/19 00:00:00 condchange: newState=true, cond=cond1689a6fa230, oldState=false
        06/17/19 00:00:00 evalchange: newState=true, cond=cond1689a6fa230, oldState=false
        06/17/19 00:00:00 condchange: newState=true, cond=grp1689a6eb162, oldState=false
        06/17/19 00:00:00 evalchange: newState=true, cond=grp1689a6eb162, oldState=false
        06/17/19 02:23:00 condchange: newState=false, cond=cond1689a6fa230, oldState=true
        06/17/19 02:23:00 evalchange: newState=false, cond=cond1689a6fa230, oldState=true
        06/17/19 02:23:00 condchange: newState=false, cond=grp1689a6eb162, oldState=true
        06/17/19 02:23:00 evalchange: newState=false, cond=grp1689a6eb162, oldState=true
        06/17/19 06:15:00 condchange: newState=true, cond=cond1689a6f51d5, oldState=false
        06/17/19 06:15:00 evalchange: newState=true, cond=cond1689a6f51d5, oldState=false
        06/17/19 06:15:00 condchange: newState=true, cond=grp1689a6f51d2, oldState=false
        06/17/19 06:15:00 evalchange: newState=true, cond=grp1689a6f51d2, oldState=false

civdusk has value 1560807653 which means Tuesday, June 18, 2019 0:40:53 [GMT+03:00], but today is June 17

You keep saying civdusk for your test but the condition is testing civdawn, so I’m a bit confused. Can you tell me in plain language what you are trying to do? Not what you think your logic is doing, but just what the goal is. I can’t reconcile this at the moment.

So, I’ve been staring at this for a bit and trying to figure out what you are trying to do, still not there, but I can give you a couple of points/thoughts…

  1. The date portion of sunrise, sunset, civdawn, civdusk is not used in the comparison; the values are stored as timestamps, but converted to hours and minutes only for the comparison.
  2. Where you live, it is very possible for civil dawn/dusk to overlap your time ranges, so you need to consider this in your logic. Your Light_OFF group uses a time range that can overlap civil dawn and civil dusk where you live.
  3. Because of the way Reactor evaluates time conditions, your Light_OFF group will go true and run its activities at 6:15am every day if your Vera is up and running at that moment (if not, it will do it as soon as possible after, as long as it’s before 11:30pm, the other half of your time condition there). The activity will be run exactly and only once during this period. If the lights are turned on again by something else/manually, it will not turn them back off. Once a condition changes state, the activity for that state runs only once; it does not repeat. It has to go through the opposite state first. This applies for all Reactor conditions.
  4. Your time() expression is only run when other conditions change. It does not run continuously. If it is your expectation that time() is being evaluated every minute, this is not what’s happening. Reactor doesn’t do that.
  5. Your time expression is equivalent to a sunrise/sunset type condition with the after operator and civdusk operand and a -30 offset. That’s how you do that test without an expression.
  6. If you have one group that turns your lights on, and one that turns them off, you must take steps in the contruction and implementation of your logic to make sure that the cannot be true at the same time, or your results will be unpredictable. If I were in your shoes, I would try to write a condition that always works for one state or the other: write the condition so it’s always true when the lights shoiuld be on, or when the lights should be off. Then, use the true and false activities of the single group to switch your lights on and off. In this way, you will usually avoid two groups trying to manipulate the same device at the same time in different ways.

Again, without a detailed explanation of your current ideas/goals, I can’t give more detailed guidance.