Using a piston to "track" status of a switch controlling a thermal actuator


1) Give a description of the problem

I’ve been using a few components in place of a smart TRV to control my CH system for some time now (thanks for the previous help!). System consists of (in part) a switch connected to a thermal actuator acting as a TRV. System isn’t running as efficiently as it could, as TRVs (or actuators) take around 90 secs to open fully. Other heating logic is built around whether this is on/off.

It’s been on my New Year List (:slight_smile: ) to improve this.

I’d like to have some kind of webcore logic which detects when the TRV is flicked on, and slowly counts up from “0” (off) to “100” (on). The value of this will be used to control a virtual switch, which in turn will be used to control the boiler.

As the moment it’s down to the TRV being ON or OFF. My idea was to have this virtual switch ONLY be on once the count has reached 100.

The current value needs to be able to be read/displayed.

Sounds like a lot, but perhaps my explanation isn’t great.

2) What is the expected behaviour?

Switch on, countdown starts from wherever is was last, and counts upwards in increments every x seconds.

Switch off, countdown starts from whatever is was last, and counts down until is reaches zero.

If I’ve switched it off, and it’s managed to get down to say, 30, then I flick it back on, it should start counting from 30 upwards. If it gets to 90, and is switched off again, it should start to count down from 90.

Once the figure has remained steady for x amount of seconds, set an external variable to reflect this.

3) What is happening/not happening?

Most of this works fine already in theory. However, occasionally during a bit of stress-testing (flicking on/off to simulate human error or a rapidly changing mind - i.e. the wife), it seems that the action of the switch change is missed. And thus the count stops entirely until you slow things down, stop, allow it to breathe again, and flick the switch again and let the logic/counters catch up with it all and return to normal.

4) Post a Green Snapshot of the pistonimage

In this image, the internal variable can be seen to update from 0 to 100 in increments of 10. After the stress testing, it sometimes stops changing.


And when it stays unchanged for 10 secs (I should have made this longer, this is just testing), then this external variable does update as planned to reflect the level.


5) Attach logs after turning logging level to Full

no logs as I think the description covers it?

If a solution is found for your question then please mark the post as the solution.


This is one is interesting. If I understand it correctly, you want to track the physical position of the valve based on direction and the amount of time the valve was in transition. Is that correct?

I’d wonder if it would make more sense to calculate the Counter upon switch transition timing.

var LastTransition Timestamp
var Counter int (or float?)

If switch changes
    Counter = ($Now - LastTransition) * (1/90)
    If Counter > 100: set counter to 100
    If Counter < 0: Set counter to 0
    LastTransition = $Now

I’m going to ponder this more and will probably come back and edit this post after tinkering a bit with some test pistons.


@ian_boje absolutely spot on. I look forward to it. It’s definitely my limited-knowledge that’s causing the problem. I’m assuming my way is probably massively inefficient, and you guys will (once again) educate me =)


Okay, here’s what I have so far:



In this one, I decided to make the position be a timestamp (Star Wars did this, didn’t they?). So, the variable position is anywhere between 0 and 90000 milliseconds (90 seconds). 0 is fully closed, and 90000 is fully open.

I’m having trouble with setting up a webcore timer based on the variable “NextEventPrediction”. I figured I could use the built-in timer to run some task at the timestamp. It seems to only work once per day, and I suspect it will run at the previous event time on the next day. Does anybody know a way to set a timer with a specific datetime that doesn’t repeat, and can be canceled?



Yes, I do (now). How’s this? I used a simple “wait for time and date” at the end of the piston. Seems to accomplish the required task.



Well, this is pretty good stuff, and clearly way over my head. Thanks so much for taking the time.

I need to be able to shut off a 2nd switch immediately when I attempt to close the TRV. So I added this to line 38:


Also added this part to the end… assuming that this is where I’d need to add any commands I’d like to execute when the valve is successfully fully opened or closed?



I hugely appreciate the help so far. From my early testing, it appears this works more consistently than mine. So I’ll mark this as a solution already.

One part I’m still missing though, is this:


Ideally, I’d like to see the actual status. i.e. if it takes say., 100 secs (not 90) to fully open or close from the completed transition, then if it’s already fully opened and I hit the ‘off’ button, after 10 secs I’d like to be able to have a variable that says “90%”, and 10 secs later, if untouched, say “80%”.

This would be a really cool way to add something visual to my dash as opposed to just sitting and waiting to see a change, if that makes sense.

Is this an easy tweak?

I’ve posted your piston with the additions I mentioned earlier.

And again, thanks so much!


Yep, that looks right.

I wondered about that, and what the best way to do that would be. Would you re-run the piston every 10 seconds? It might make sense to use global variables, then have a second piston watch the transition and update a status indicator somewhere. To calculate that, it would probably be something like this:

Position = Position + ($now - LastTransitionTime * CurrentDirection)

Where were you going to show the current status? Obviously, the logs show the status when you flip the switch, but that might not be helpful if you’re not in front of your computer.

This was a proof-of-concept of sorts. It might need some re-arranging to make it work 100%.

To adjust from 90 seconds, you’d have to change every instance of 90000 to whatever milliseconds the device takes to transition. If you’re going to do that, I’d probably change it to a constant variable, so you can more easily adjust it later if needed.


I’m afraid you’ve lost me a little with that =/

I have however altered the piston and added a few variables to allow me to alter the TRV in question a little easier, and I’ve altered the input to seconds instead of milliseconds.

Where were you going to show the current status?

On my sharptools dash, for hubitat

My thoughts would be…

After switch is flicked, here’s the info your piston provides:


…and we know the duration (90 secs).

Ah, I’m going to have to leave it there for a few - it’s past midnight and the baby isnt working wonders with my concentration = P Shall return with a clearer mind soon. =)


Oh, I’ll try to add more detail.

Position: This is where I assume the valve is (between 0 and 90000 (or 90 if you adjusted it))
$now: The current time. In webcore, this is just a very big number in milliseconds. Add 1000, you’re adding 1 second.
LastTransitionTime: This is set to the value of $now, but when the switch is flipped.
CurrentDirection: Either -1 or +1. This variable doesn’t exist (yet). It would relate to the switch being off (decreasing) or on (increasing).

Interesting. Would you be able to use a virtual dimmer to represent the value? If 100%, fully open and 0% at fully closed?

I thought about the updates a little more. At the end, instead of having a delay to the estimated complete time, could you just do what you had initially done?


Virtual dimmer is an excellent idea. Working all day today so I’ll not get a chance to think about any of this any more until late tonight.

All I need really is to get my head around how to periodically use your approach to pull out a percentage figure.

The problem with my original was that the logic occasionally died/paused if there were rapid changes. Not sure right now how to combine. But its defo something in the area of percentages and repeat loops, probably =p


How does the valve on your TRV work? Would you be able to attach a multipurpose sensor to it to determine the orientation of the valve?


Sorry. Been busy work / boring tasks.

Not really possible to use a sensor. But I had another thought and a quick go.

Renamed the Piston to ‘transit’ and added a global variable (true/false) to indicate when it’s either opening or closing (in theory)

Added a second Piston to start counting up in increments of 10 every 5 seconds when @in_transit gv switches to TRUE

The count does start/stop as expected as a test. Thought was I just need to add something to the initial Piston to set another GV to define to ‘current’ position when in transit begins. I.E if full path is 100 secs, and predicted time til closed is 50 secs from $now, then the start value is already 50%.

Then I guess I just need to pass another GV to let 2nd Piston know whether its opening or closing to tell it whether to count up or down.

So if its currently opening, and already defined as being at 50% (midst a 100 sec cycle), then set initial count to 50 adding 10% every 10 whilst @in_transit is true.

This is all new to me as you may have gathered. So I’m googling and adapting your Piston to suite.

Sound good?

For reference, this is the thermal actuator


Works ace.


Combined this into one piston. At the minute, the percentages are menaningless - just adds/subtracts 10% either way. Work in progress =p