Local Variable Help


#1

I figured out how to use a local variable, or at least I think I did. This one is doing what I expected and is including the current temperature of a device. I’m not sure if the variable is being used correctly though… What I’d like to know is if there is a way to write it so it the SMS it sends has both the temperature (it does now) and if the temperature is rising or dropping. (presumably over a recent period of time)

This piston just reports what is happening, but this could be used in another piston to actually do or not do stuff.

Example: The temperature is 20* and dropping, don’t open door, or the temperature is 20* and rising, open door.

…and this is the piston that actually does the work. I’m wondering if it could be something like… temperature is 12* and rising, turn on. (otherwise the condition is not true.)


#2

Rising or dropping? My first thought is, as we approach sunrise, the temperature can normally be expected to be rising (or about to start rising)… So maybe we can default to “rising” at that time?

Although, if you want this logic used at other times, here is one approach for static times:

define
   integer tempPrev = (no value set)
   integer tempNow = (no value set)
   string direction = (no value set)
end define

execute
 ϟ IF Time happens daily at 1PM  <-- Trigger
      Set variable {tempPrev} = Device's temperature
   END IF
 ϟ IF Time happens daily at 2PM  <-- Trigger
      Set variable {tempNow} = Device's temperature
         IF {tempNow} is greater than {tempPrev}
         Then
            Set variable {direction} = Rising
         ELSE
            Set variable {direction} = Dropping
         END IF
      Send SMS "Outside temp is currently {tempNow} and {direction}"
   END IF
end execute

Note:

It will take two normal executions for this piston to work. (both times must pass normally) IE: Pressing Test won’t do anything. You can tweak the times during testing so you don’t have to wait so long.


#3

If we want this logic on a rolling time slot, here is food for thought:

define
   integer tempPrev = (no value set)
   integer tempNow = (no value set)
   integer diff = (no value set)
   string dirNow = (no value set)
   string dirPrev = (no value set)
end define

execute
   Every 30 minutes
      Set variable {tempPrev} = {tempNow}
      Set variable {tempNow} = Device's temperature
      Set variable {diff} = {tempNow} - [tempPrev}
      Set variable {dirPrev} = {dirNow}

         IF {difference} is greater than 0
         Then
            Set variable {dirNow} = "Rose"
         ELSE
            Set variable {dirNow} = "Dropped"
         END IF

         IF {dirNow} is not equal to {dirPrev}
         Then
            Send SMS "Temp is currently {tempNow}.  {dirNow} {diff} ° in the past 30min)"
         END IF

   END EVERY
END EXECUTE

Note this structure is bare bones… In this example, SMS will only be sent when the temperature begins to rise, or begins to drop. (likely 2-4 times a day)

Alternatively, you can push the results to a @globalVariable so other pistons have access to this data.


Pro Tip:

If your device uses decimals, you can define the first 3 integers as decimals


#4

WOW!

That gives me lots to think about… Something you mentioned got me thinking about the temps at sunrise, which looking at history, seems to be lowest around 6:00 AM, so… depending on when sunrise is, it might not be rising at “trigger time”.

It’s not that critical, so maybe I could just base the trigger on the forecasted high temperature using $twcweather.forecast.temperatureMax[0]

Is this relatively dependable? (twcweather)


#5

While TWC can’t be a direct trigger, there is nothing stopping you from pulling that data and then using that in a conditional query. (IE: you will need something else to fire off the piston)

For a few examples, you can base the trigger on:

  • Time (static), or
  • Sun (Sunrise -15 min), or
  • Motion (First motion in the kitchen after 6am), etc…

Note that last one won’t work if you have pets. :sunglasses:


#6

This is my first variable of any kind.
My hope is that this will be reliable (on the forecast side) meaning will there “ALWAYS” be a forecasted temperature with twc? What would happen if there is no forecasted temperature at sunrise?

My attempt below:


#7

TWC is fairly decent… but [0] can be a fickle beast!!!

For this piston (around sunrise), you should be OK… but before applying [0] to other pistons, I would highly recommend reading the top of this section in the wiki.


TL;DR

20+ hours a day, [0] is today…
3+ hours a day, [1] is today…
with events during the 3am hour potentially going in either direction


#8

The IF block would fail, and no action would be taken


#9

Fair enough…

Would you know how reliable this would be? (the getting of the forecast temperature, not the actual forecast… LOL)

Sorry… just saw your previous response…


#10

One trick that I normally use, is to NOT set the variable up top in the define section. I leave that (no value set)… Later on in the code, I use the command “Set variable”.

This extra step has a few benefits… one of which is you will always be able to see exactly what webCoRE saw at the last execution. (It’ll be stored up top in that ‘define’ section)

This one step alone makes troubleshooting most pistons so much easier.


With TWC, usually server side errors return null… and often, null is seen as zero. So for example, you could create a “safety net” at the very bottom…

IF {Forecast_High} is less than 1
    Then Send SMS "Alert bad data from TWC"
END IF

This won’t turn on Switch 4, but it will at least alert you to something strange.


#11

Hmm. can you show me an example of how that would work? Does it matter where it goes in the bottom? This is what worked this AM…

I like the safety net idea. I think I can get that to work!

Thank you!


#12

Sure. Most of my variables have an “Initial value” of (no value set).

temp

This means the variable will never change unless the code tells it to. In your case, you want that data refreshed each time the piston runs. For example, You could place it up top… Outside of your current IF block.

execute
   With Location
      Do Set variable Forecasted_High = $twc.etc.etc
   END WITH
   IF Time happens Daily at ...
      ...Current logic here...
   END IF
END EXECUTE

Pro Tip:

You’ll have to create the new block at the bottom, and then drag & drop it to the top.


#13

Thank you…
Question???
If the variable up top does nothing, why does it go there?

I think I followed along… I tried this one… It works, but I don’t know why. Can you explain why this works? I also don’t know why it changed my 15* on line 29 to false.


#14

A variable still needs to be defined up top… but by leaving it set to the default (no value set), it will give you more information during all future troubleshooting.


I believe line 17 should be defined as an integer variable(Not boolean)
I apologize for my misleading image above…

To say this another way, a ‘booleanvariable can only be true or false…
While an ‘integervariable can be any whole number.

After you fix that, take another look at line 29, and correct if needed.


#15

Okay—

I tried this, but it does not turn on outlet 1.

It seems to change the variable up top to 0.

Here is the green snap and the logs from when I set a time for it to run instead of waiting for sunrise…

11/25/2021, 5:20:59 PM +124ms
+0ms ╔Received event [Home].time = 1637878860000 with a delay of -876ms
+45ms ║RunTime Analysis CS > 18ms > PS > 8ms > PE > 19ms > CE
+47ms ║Runtime (38405 bytes) successfully initialized in 8ms (v0.3.113.20210203) (46ms)
+48ms ║╔Execution stage started
+52ms ║║Cancelling statement #1’s schedules…
+73ms ║║Executed virtual command setVariable (3ms)
+77ms ║║Comparison (time) 62459199 happens_daily_at (time) 62460000 = true (0ms)
+78ms ║║Time restriction check passed
+79ms ║║Cancelling condition #14’s schedules…
+80ms ║║Condition #14 evaluated true (5ms)
+81ms ║║Cancelling statement #14’s schedules…
+84ms ║║Requesting time schedule wake up at Fri, Nov 26 2021 @ 5:21:00 PM EST
+94ms ║║Comparison (decimal) 45.67 is_greater_than (integer) 12 = true (1ms)
+96ms ║║Condition #3 evaluated true (9ms)
+103ms ║║Comparison (enum) off is_not (string) on = true (1ms)
+104ms ║║Condition #8 evaluated true (8ms)
+108ms ║║Comparison (integer) 0 is_greater_than_or_equal_to (integer) 15 = false (1ms)
+109ms ║║Condition #12 evaluated false (4ms)
+110ms ║║Condition group #13 evaluated false (state did not change) (35ms)
+112ms ║╚Execution stage complete. (64ms)
+113ms ║Setting up scheduled job for Fri, Nov 26 2021 @ 5:21:00 PM EST (in 86400s)
+121ms ╚Event processed successfully (121ms)

This is what the top variable automatically changed to:

//**************************************************************/ defineinteger twcHIGH; / 0 */


#16

Could this be because it is 2.5 hours after 3PM and I’m using twc?


#17

Yes. [0] returns null in the late afternoon & early evening.

(you could test using [1] which is tomorrow)


#18

That worked!

What do you think about setting up a Piston that would run every day at say… 6:00 PM and retrieve ALL the values from twc I might need to use TOMORROW as Global Variables like this?


#19

That could work… as long as you remember that your @globals will only be accurate for the current day from midnight until 6:17PM.

IE: The moment this piston runs, the @globals will be inaccurate for the next 5.7 hours… (and you will no longer be able to access TODAY’s forecast.


As an alternative… I would recommend grabbing tomorrow’s data [1] at 11:50PM. This effectively makes your global accurate for 99% of the time.


Correction on TWC Forecast (resets once in the 3AM hour):

$twcweather.forecast.temperatureMax[0] = Today
$twcweather.forecast.temperatureMax[1] = Tomorrow

Sorry about that. I was mixing up TWC’s quirks…


For reference, daypart returns differently (resets twice in the 3 o’clock hours):

$twcweather.forecast.daypart[0] is this morning…
$twcweather.forecast.daypart[1] is tonight…
$twcweather.forecast.daypart[2] is tomorrow morning…

Editing my previous text now.


#20

That’s what I will do. 99% is great!!
Thank you!