Expression code isn't working but should be

I have an expression tag that is toggling a bit and holding it on for a few seconds using the following code: (getHour24(now())) = 6 && (getMinute(now())) = 0 && (getSecond(now())) <= 5
As far as I understand this it should be turning on my bit for 5 seconds at 6am, which is what I’m trying to do, but while testing with different values I haven’t been able to get the bit to change state. When I remove the gethour24 function it triggers no problem every time but its not ideal because its every hour instead of just at 6am. I am hoping that someone with more ignition experience can point out something that I may be missing or a syntax error.

I would take a look at your Execution Mode, and probably set it to a fixed rate.

The expression code seems to be valid since I copied it into my system and only tweaked the number values to get a trigger that would work.

Ok thanks for your help, I knew my code should work.
But I’m afraid I don’t know what you mean by Execution Mode, I’ve never heard that term before and a quick google search didn’t yield much.
Also here is some more info that might be helpful. The reason I am toggling a bit is so that I can run a tag event script on it’s value changing. Not sure if that would impact the execution of the tag’s expression though.

This is from 8.0, but there should be a setting similar in 7.9. In theory, I would think event driven would work, but Fixed Rate will re-evaluate at the interval you choose.

I tried your expression as well, it worked fine for me on 7.9.12. Check the scan class on the tag, it should be a second or less.

For completeness, 7.9 does not have Execution mode. All tags are assigned to a scan class.

For this type of application, I use an expression tag that returns the time as a string. I call mine CurrentTime:

dateFormat(now(), "HH:mm:ss")

Then, for every place I need a trigger based on a time, it expression would look like:

timeBetween({[~]CurrentTime}, "6:00:00", "6:00:05")

This makes it easier to read, because I’m old, and I don’t want to use too many brain cells decoding what I wrote. :slight_smile:

2 Likes

Thank you, I figured out what my problem was and why it wasn’t working thanks to your current time example. Turns out the time on the tag servers is not the same as my local desktop which is why it wouldn’t work as expected when I expected it. Thanks again everyone for your help.

I was curious about your solution, so I tried it. It doesn’t work in the timeBetween tag. It says cannot coerce {[~]CurrentTime} to java.util.date. The only way the current time tag works is configured as string though.

Every time I encounter this sort of thing, I ask: why do you want that boolean to turn on for a few seconds at that time of day? The answer is almost always: I/We want to run X every day at that time, using a tag change event.

Getting this to work this way requires the sun, the moon, and the stars to all align (funky expression, scan class timing, and event script that checks for initial conditions and anti-repeats). A better solution is to use a gateway timer event paired with a Date memory tag. The memory tag holds the last execution timestamp. The timer script checks current timestamp against the last execution (to prevent double runs) and checks for the appropriate hour/minute/second. When it decides to run again, it starts by updating the memory tag. This approach can be used for once-a-day, once-a-shift, once-an-hour, once-a-minute, or any other “once per” you can conceive. And this approach keeps all relevant logic and timing criteria in a single, easily maintained place.

1 Like

Seems like I remember this coming up before, here was some script written by @pturmel. Personally, I wouldn’t mind ignition having a linux type crontab for these kinds of things

from java.util import Date
lastTrigPath = '[default]some/path/to/datetime/tag'

# Simple function to convert any timestamp to the trigger point on the same day
def truncateToTrigger(ts):
	return Date(ts.year, ts.month, ts.date, 16, 0, 0)

# Check if time to run the triggered event.  Call from timer script
def checkTrigger():
	last = system.tag.read(lastTrigPath).value
	nextTrig = truncateToTrigger(last)
	if nextTrig.time < last.time:
		nextTrig = system.date.addDays(nextTrig, 1)
	now = Date()
	if nextTrig.time <= now.time:
		system.tag.write(lastTrigPath, now)
		# Do the trigger stuff here

Well, yes, because timeBetween expects a string. Good catch, though. :slight_smile:

I still can’t log in to the ideas portal, or I’d make a formal suggestion there. I agree that timer events ought to have this as an option.

(After logging in to the ideas portal via the shared account page, the redirect back to canny.io still shows not logged in. Further attempts to login are just flipped back to canny.io, still not logged in. I suspect it is a cross-domain scripting issue.)

Turns out there is a planned feature:

https://inductiveautomation.canny.io/ignition-features-and-ideas/p/gateway-script-type-triggered-at-specific-time

I even commented on it back when I could still log in.

3 Likes

You also can schedule a blank report with a script execute for things too if you have the reporting module,

3 Likes

Having done this before: if you do go this route, be sure to document it!

It’s not obvious to the next guy, or yourself at a later date, that scripts are being triggered by report schedules.