SOLVED - For Loop, or should I use something else? Checking power usage to control another Piston


#1

1) Give a description of the problem
Not sure if a For Loop should be used in this piston or some other solution. If a For Loop is the correct tool, how do I configure it correctly so it runs 20 times and then stops, but also stops if the next condition is met?

2) What is the expected behavior?

  1. If Dryer door contact changes to open, then every 30 seconds for the next 10 minutes get Current Power of the Dryer.
  2. If Dryer power stays greater than 10W for 40 seconds, then set variable @isDryerRunning = true.
    a. should this condition be an Else of condition #1? (sorry, I don’t have a proper understanding of the else function)
    b. Ideally, this loop would stop if condition 2 is met
  3. If @isDryerRunning = true, get Dryer power every 15 seconds.
  4. If @DryerHasFinished (in another piston) = true, set variable @isDryerRunning = false

3) What is happening/not happening?
It seems to run every 4 seconds or so. I think it has to do with the inital check not stopping once the condition is met (that makes it check every 15 seconds)??

4) Post a Green Snapshot of the pistonimage

5) Attach any logs (From ST IDE and by turning logging level to Full)
I will post logs here after I get some initial feedback

.

EDIT: Question has been solved with a big thanks to @Mike1616, who spent a lot of time educating and helping me understand, offering an alternate solution.

As a noob, the settings required for a For Loop were not obvious. For others new to this, as a general example, these settings in a For Loop, will make an action run 10 times;

and will result in the code like this;

image

Through my experimentation I tried to add a Time variable, and this is the solution I ended up using;

image


How To Exit Out Of Loop
#2

After checking out some other pistons, I think I found a way to set a timer, but would still like feedback from anyone who knows what they are doing :smile:

Which feeds this;

Should I combine the 2 of these together? If so, recommendations…

To show the full picture of what I am trying to achieve, the 2nd one feeds this;

Which then feeds this;

Which ones could/should I combine, and how?


#3

The overall idea is that if the Dryer Door is closed, for the next 10 minutes, check/report the power level of the Dryer every 20 seconds.

If in that 10 minutes, the power raises above 50w, stop this checking/reporting, and instead check/report the Dryer power every 15 seconds until the dryer door contact changes to open.

Once the power levels have gone above 50w for 30 seconds, and then droped below 30w for 30seconds, alert me (various ways).

If I haven’t gotten the clothes out of the dryer after 2 minutes, keep alerting me until I do.


#4

Why?

Yeah, that makes sense…and a good way to tell if the dryer is running You don’t need the door at all this way.

Not necessary. You just care when the dryer stops using as much power. That’s the trigger when it’s done.

Too many pistons…you should be able to do everything in one.

Now for some other thoughts…

In your “nf2we” piston, the statement “Time is 10 minutes past $now” will never be true. Because those two things are equal and will always be equal. If you want to use something like that you’d have to set a variable for 10 minutes after the last time you checked (and then update it again). But you shouldn’t need that anyway.

If you goal is to just get notified when the dryer is done…then simply watch for the power to go above a threshold (50 watts is a good choice). Then set your “IsRunning” variable. Then watch for it to stay below a value and then you’ll know it’s done.

Here’s my Dryer monitor piston if you want to compare. This is all of it…just one piston.


#5

Ha ha, I know it is nuts to have it spread across 4 pistons - and I do want to reduce that. Here’s a little background…

Originally I had just the Dryer is Finished 1 & 2, and they were working well together. Then I changed my plug from a Wemo, to a TP-link HS110. It didn’t seem to be reporting very often, and as a result, not activating the piston. The creator of the DH did some work over the weekend to get the DH suitable for my Australian versions of the HS110 working. I posed the following to him;

Now, I am new to webcore (and any sort of coding for that matter), but based on the pistons I have cobbled together (which are mostly based on other people’s pistons), the other thing I had been thinking to do (instead of having the refresh rate set at 5 minutes, 24/7), was to have a rule that;

* If Dryer door contact changes to open, then every 30 seconds for the next 10 minutes poll the Dryer. Edit - this assumes polling will report power usage/wattage
* If Dryer power stays greater than 10W for 40 seconds, then set variable @isDryerRunning = true.
* If @isDryerRunning = true, poll the Dryer ever 15 seconds.
* If @DryerHasFinished (in The Dryer has Finished piston above) = true, set variable @isDryerRunning = false

So the reason was to have the plug just be polled when it was likely to be in use a couple of times a week instead of 24/7.

Happy you responded to this. I am new to coding and don’t even know what I don’t know. I originally had it as a For Loop, but that didn’t work - obviously had the parameters wrong. From the rule you can probably see that I basically wanted a countdown timer that reported the power usage every 30 seconds, for 10 minutes, but to stop if the power reported was above 50w.

Are you able to shed some light on how to do a countdown timer, or what a For Loop would look like for this situation?

Thanks for sharing the piston. In your code, lines 37 & 48, can you tell me what this does?
{addminutes($now, -2)}

Thanks for your help, and any further info you can provide. As a noob to SmartThings, WebCoRE, and any sort of coding terminology, it is a steep learning curve.


#6

Sorry, forgot this bit. I am notorious for going to check the washer/dryer, and getting distracted by my computer (which I have to walk past to go to the laundry). By the time I check email (or whatever), I have usually forgotton about the clothes. I can repeat this process and it gets to the end of the day and the clothes are still sitting in the washer waiting for the dryer, or in the dryer, now creased. This is what I have the Dryer is Finished (2 of 2) reminder loop :blush:


#7

Alright… I get a little more about your use case…and I think we’re able to do this…I’ll just have to put aside my desire to re-write everything you’ve done up until now. :slight_smile: I’m joking a bit there…you’ve got a good framework from which to start…I’m just not a fan of the global variables and having it across four pistons. But if you’re going to have it across even more than one piston then you’re going to need globals to do it.

In truth I used to forget about my laundry all the time too…which is why I turn on a bank of lights at the end as my other notification (that’s what the “Keypad 6” is at the end there). Not sure why WC changes it that way, it’s a light switch… Another option would be to turn on a light and set it to a color and not turn it off till you’ve opened the door to the machine again. That would be another thing to consider.

Alright so addMinutes is a built-in WC function (see https://wiki.webcore.co/Functions) that allows you to take a variable in a datetime format and as the name implies add some minutes to it. In my case I want to actually subtract some minutes, so I’m adding -2 minutes, which is the same as taking away two minutes from how it is set now. If you don’t understand the concept for a variable, then read this: https://wiki.webcore.co/Variable

So in your case, if you want to make a while loop that ends 10 minutes from now, the correct way to construct that would be to declare a variable at the top which will hold date and time information. Then set the variable to be equal to the system variable for the current time ($now) but 10 minutes in the future.

Which…as I believe you were putting together, would look something like:

Set variable endLoopTime = addMinutes($now, 10)

Then to check your loop you would use this variable as it would then be set with a future time in it.

Until Time is after endLoopTime

We might have to take a few bites at this since you’ve got so many moving pieces here…but take a look at the WC functions that you can use, read up on variables and then put the changes I’ve shown here into place in your loops. Then post what you’ve got and I’ll look it over again.

What you want is entirely possible…it will likely just take a few more iterations to get there.


#8

Thanks again for your time and knowledge. By the way, I have no problem with you putting aside what I have done and re-writing it. The reason I have done what I have is that they are based on what other’s have done. I have used their pistons as a base, and then adapted/changed and added to them to get what I needed. Well, that explains Dryer has Finished 1 & 2. If it makes more sense to have the same functionality of those 2 combined into 1, I am very happy to do that. With Dryer Power 1 & 2, as mentioned in the previous post, that was just an attempt to see if I could get regular power info - just when I needed it - but they aren’t necessary. I did it to see if I could do it, and to try to learn along the way.

Loops, thought I would put down my thoughts going forward so you can understand my thought process…
After reading this;

my first thought was just to just see if I could amend line 41 (that you said could never occur):

image

Curiosity got me and I thought I would duplicate the piston, and change it to test with some lights (rather than running the dryer (it is 6am here and the family is all asleep)

image

That didn’t work. The light toggled correctly, but it just kept cycling.

The next step was to create a basic For Loop for testing :smile:

It only toggled once. Logs

Can you walk me through what should be in the different parameters of the for loop? The only way I could see to get the variables in, was to do them as Expressions. For the above attempt, I had set it like this;

Thoughts?


#9

Alright I’m going to show you how to setup a time based loop so that you’ll have that in your bag of tricks, but then I’m also going to explain to you why that is entirely irrelevant in this particular piston. This is a recreation of the “nf2we” piston.

Now let’s go over this… First and foremost, before we do anything we need to declare a variable which we’re going to store the current date and time into. That’s done on Line 17.

Then before we enter the loop, we need to put into that variable the current time information, with an offset of 10 minutes. This will give us something we can compare against at the end of each loop. Is time past this value. That’s a definitive check. If we just kept comparing Time against the system value for the current time ($now) we’d be in an infinite loop. So that’s line 24. Variables can be set in the “Location” section of a piston. There are many useful things in the “Location” section. Hopefully this piston demo shows you how to get to them for next time.

Now, look at the difference on Line 36. Time is after LoopEndTime. That’s everything right there. That’s something which can and will become true. It has a specific value, $now is ever changing. Every time you ask “what is the value of $now” you always get the current time. That’s why we need to store a value in a variable…so we have something to compare the current time against.

So that’s how you make a time based loop.

Now, having said all of that… I want to call your attention to Line 40. Nothing in this entire piston really matters because of Line 40. Why? Well, because Line 40 is a trigger. The little lightning bolt next to it tells you that webCoRE is monitoring for that item independently and the whole piston will run based on events from that device. Also, where it is placed in the piston (meaning it is NOT inside the IF block) means that it will run all the time. To be clear, this piston will not sit around and wait for your loop to complete. It does not care about that. If the power rises above 20w then it’s going to set the variable to be true. It’s that simple.

One little if statement does it all…based on how it is written and where it is placed. So…since this piston is going to set that variable as soon as the device goes over 20 watts, it begs the question of whether or not you even need anything that came before that.

I guarantee you that the piston is not going to sit waiting in the While loop for the power to go over 50 watts before setting that variable to true. As soon as it goes over 20 it’s going to get set.


#10

Here’s a simple solution. 2 pistons…keeping all the work you’ve already done on the one which loops for your notifications. Thus still using a global variable. This could get shrunk down into one still…but this is simple enough. Add your own notifications back into this one where I’ve commented below.

And here’s your notify piston, reworked a bit (based on my experience this structure will work a bit better).


#11

Thanks, that all makes sense, and I can see how you have done that. I will keep a note of this for future reference in a doc I have for myself - bag of tricks is growing. :smile:

Yep, I see what you are saying. The point of this piston was to get the plug to report its power as required, rather than every 5 minutes 24/7. In testing the other day, the plug wasn’t reporting power in the logs, even though it was part way through a drying cycle and I wanted a way to force it to check/report.

For line 40, I chose 20W here as a way for me to easily differentiate (compared to line 34) what was happening in the logs. Originally I had them both set at 50W and to me the logs were a jumble. Again, I don’t know what I am doing :). I knew that they would become true basically at the same time. If the dryer is on, but not in a cycle, its power is about 5W. When it kicks into drying mode, it shoots well up into the 100’s within a second or two.

OK, that has been a good education. Now I will check out your next solution. Thank you.


#12

So the 2 you have done above (Dryer & Notification Loop), they look quite similar to what I had. Is your Dryer rule more stable because it doesn’t have an Else if condition, and just stays with if/then components? Or for some other reason??

There are so many different ways to achieve the same thing - it makes my head spin.

On another note… In layman’s terms, if and then are pretty straightforward;
If this condition is true/happens, then do this.

Does Else if just mean; but if?
If this condition is true, then do this, but if this happens…

Thanks again for really taking the time to explain how things work. It would be great if there was a webCoRE for dummies section in the wiki that listed a bunch of examples that had a description, then the code, and then even a step by step (with pictures) of how to do it. I guess the assumption is that if you are messing around with this stuff, you must have at least a basic understanding of coding??


#13

Basically that has to do with the way Triggers work. I just chose to do it that way because that’s really how it’s going to work anyway based on the events which will cause the piston to run.

True. But in a month you’ll start to be able to tread water. :slight_smile:

There are two different possibilities here.
IF > THEN > ELSE
or
IF > THEN > ELSE IF

Those are two entirely different constructs.

IF > THEN > ELSE is like saying…
IF this thing is true, then do it, otherwise just do this other thing.
So, IF my favorite team won the game, say Hooray, otherwise say Boo.

IF > THEN > ELSE IF is like saying
Check if this thing is true, and if it is do this, otherwise check to see if this other thing is true and if it is do it.
So the ELSE IF allows you to do another true/false test. You can string multiple of those together, and you can follow all of that with an ELSE at the end too. So a really silly example would be something like:

IF today is Monday, then put on a red shirt
ELSE IF today is Tuesday, then put on a green shirt
ELSE IF today is Wednesday, then put on a blue shirt
ELSE IF today is Thursday or Friday, then put on a purple shirt
ELSE Put on a black shirt

In that example, every statement could get evaluated, but when the first true one is found the rest of them get skipped over. Otherwise if none of them were true (say if it was Saturday) then the last ELSE statement would be ran since it’s the catch all.


ELSE IF or not ;)
#14

Thanks for the explanation (going straight to my reference doc :slight_smile:)

If I could, I wanted to pick your brain about a rule I plan to create in the future. When WeatherFlow releases the 2nd part of their Smart Weather Station, they will then work on ST integration. When that happens I will be good to go. That part of it should be pretty straightforward, but the part I need help with can be figured out now.

The rule would activate via a variable (see, I am learning :smile:). The variable would need to check that the play state on a particular Sonos speaker is Playing (or not Stopped or Paused). I have had a little look at this, but I am getting it wrong. Any idea on how to code this play state check?


#15

Yes, you are learning, but we still need to work on your terminology a bit…:slight_smile:

Variables can’t check anything. They just exist. They are really containers for information that your program can use. So a variable can’t do anything it can only store information and tell you what is stored in it. Now you can make a piston which triggers when a variable has changed… I might be splitting hairs here…but I like being technically precise. :slight_smile:

Now to your question on the Sonos. I’ll be honest I don’t have any of those nor any smart speaker. I’ve been thinking about them though but I haven’t decided to go for any of them yet. So unfortunately I don’t think I can be very helpful on the specifics on them. General piston questions I could likely help you out with even though I don’t have one, but if you want to know the specific state of the device that’s something you’re probably better off asking the community about in a new thread.


#16

Ha ha, I absolutely agree. I the more precise I can be with terminology, the more likely I am to get the desired result when stating a problem or posing a question. I will work on that.

I will open a new topic for the Sonos question.

Well, I will close this one off. Thanks again for your help and teaching, it is much appreciated.