Waiting for certain time to send email with executeAndDistribute

Hi,

Is there a better way to send reports with system.report.executeAndDistribute() at a specified time through tag event scripting?

This uses time.sleep and waits until ‘work hours’ to send the report.

hourOfDay =  system.date.getHour24(system.date.now())
minuteOfHour = system.date.getMinute(system.date.now())
floatOfDay = hourOfDay + minuteOfHour / 60.0
print floatOfDay
#start time at hour 7, end time at hour 17
workStartHour = 7.0
workEndHour = 17.0
if floatOfDay < workStartHour or floatOfDay > workEndHour:
	from time import sleep
	diffTime = workStartHour-floatOfDay
	if diffTime > 0: 	
		hoursTillWork = diffTime * 60 * 60 #convert to seconds
		print 'y'
	else:
		hoursTillWork = (24 + diffTime) * 60 * 60
		print 'x'
	sleep(hoursTillWork)
	print 'a', hoursTillWork
	#generate report after waiting
	#system.report.executeAndDistribute()
else:
	print 'b'
	#generate report now
	#system.report.executeAndDistribute()

Just making sure this isn’t using unnecessary overhead.

This is probably not a good idea, because you’re holding onto the thread for hoursTillWord hours.

A better (but probably still not best) solution would be to place this into a Gateway Timer Script which executes every hour (or some time differential you determine) to check if it’s “working hours” before executing the report.

If doing this, you should also make a check against a tag which determines if the report has already been run once “today” to prevent this script from sending the report multiple times.

hourOfDay =  system.date.getHour24(system.date.now())
minuteOfHour = system.date.getMinute(system.date.now())
floatOfDay = hourOfDay + minuteOfHour / 60.0
print floatOfDay
#start time at hour 7, end time at hour 17
workStartHour = 7.0
workEndHour = 17.0
tagPath = "tag_which_determines_execution"
reportAlreadySent = system.tag.readBlocking([tagPath], timeout)[0].value
timeout = 3000
if (floatOfDay > workStartHour) and (floatOfDay < workEndHour) and (not reportAlreadySent):
	system.report.executeAndDistribute()
    system.tag.writeBlocking([tagPath], [True], timeout)
else:
	system.tag.writeBlocking([tagPath], [False], timeout)

*Use system.tag.read() and system.tag.write() if using a version before 8.0.

Great, thanks for the quick reply.

The emails seem to be sending now, but there is an INDENT EOF error occurring after the script runs. I’m not sure if this is a cause for concern or how to prevent the error.

FWIW, this code is in a Gateway Event Timer Script contained within a for loop.

			def sendEmail(tankNo=tankNo, tank = tank):	
				import system
				recipients=["jane@test.com","jon@xyz.com"] #
				system.report.executeAndDistribute(path="xyz", parameters = {"tankNumber":tankNo}, project="xyz", action= "email", actionSettings = {"to":recipients, "smtpServerName":"Mail Server", "from":"jon@xyz.com", "subject":tank + 'test email', "body":tank + " test "})
			system.util.invokeAsynchronous(sendEmail)
			print 'post-email function'
#end of gateway timer script

INFO   | jvm 1    | 2019/07/24 09:51:50 | post-email function
INFO   | jvm 1    | 2019/07/24 09:51:50 | W [r.Data                        ] [17:51:50]: Unable to compile script. 
INFO   | jvm 1    | 2019/07/24 09:51:50 | org.python.core.PySyntaxError: SyntaxError: ("mismatched input '<EOF>' expecting INDENT", ('<function:updateData>', 1, 29, 'def updateData(data, sample):\n'))
INFO   | jvm 1    | 2019/07/24 09:51:50 | 
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at org.python.core.ParserFacade.fixParseError(ParserFacade.java:92)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at org.python.core.ParserFacade.parse(ParserFacade.java:199)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at org.python.core.Py.compile_flags(Py.java:1751)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at com.inductiveautomation.ignition.common.script.ScriptManager.compileFunction(ScriptManager.java:689)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at com.inductiveautomation.ignition.common.script.ScriptManager.compileFunction(ScriptManager.java:673)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at com.inductiveautomation.reporting.gateway.data.ScriptReportDataSource.gatherData(ScriptReportDataSource.java:50)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at com.inductiveautomation.reporting.gateway.ReportingGatewayHook.getReportData(ReportingGatewayHook.java:338)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at com.inductiveautomation.reporting.gateway.ReportingGatewayHook.getReportData(ReportingGatewayHook.java:239)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at com.inductiveautomation.reporting.gateway.scripting.GatewayScriptingFunctions.executeAndDistribute(GatewayScriptingFunctions.java:290)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at com.inductiveautomation.reporting.common.scripting.ReportScriptingFunctionsPyWrapper.executeAndDistribute(ReportScriptingFunctionsPyWrapper.java:74)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at java.lang.reflect.Method.invoke(Unknown Source)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:186)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction.__call__(ScriptManager.java:429)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at org.python.core.PyObject.__call__(PyObject.java:320)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at org.python.pycode._pyx156.sendEmail$1(<TimerScript:xyz/checkWorkHours10min @10,000ms >:64)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at org.python.pycode._pyx156.call_function(<TimerScript:xyz/checkWorkHours10min @10,000ms >)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at org.python.core.PyTableCode.call(PyTableCode.java:165)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at org.python.core.PyBaseCode.call(PyBaseCode.java:301)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at org.python.core.PyFunction.function___call__(PyFunction.java:376)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at org.python.core.PyFunction.__call__(PyFunction.java:371)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at org.python.core.PyFunction.__call__(PyFunction.java:361)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at org.python.core.PyFunction.__call__(PyFunction.java:356)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:647)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at com.inductiveautomation.ignition.gateway.script.GatewaySystemUtilities$1.run(GatewaySystemUtilities.java:69)
INFO   | jvm 1    | 2019/07/24 09:51:50 | 	at java.lang.Thread.run(Unknown Source)

Is the updateData function the issue? If it is, I don’t where the function is located.

I think the supplied code is the issue:

    def sendEmail(tankNo=tankNo, tank = tank):	
		import system
		recipients=["jane@test.com","jon@xyz.com"] #
		system.report.executeAndDistribute(path="xyz", parameters = {"tankNumber":tankNo}, project="xyz", action= "email", actionSettings = {"to":recipients, "smtpServerName":"Mail Server", "from":"jon@xyz.com", "subject":tank + 'test email', "body":tank + " test "})
	system.util.invokeAsynchronous(sendEmail)
	print 'post-email function'

COULD be the problem because indentation and lines mean something in Python.

try:

def sendEmail(tankNo=tankNo, tank = tank):	
	import system
	recipients=["jane@test.com","jon@xyz.com"] #
	system.report.executeAndDistribute(path="xyz", parameters = {"tankNumber":tankNo}, project="xyz", action= "email", actionSettings = {"to":recipients, "smtpServerName":"Mail Server", "from":"jon@xyz.com", "subject":tank + 'test email', "body":tank + " test "})
	
system.util.invokeAsynchronous(sendEmail)
print 'post-email function'

if that doesn’t work, then what you should look for are instances where:
you have a conditional statement which contains no logic (an if: or for which does nothing)

OR it could be because the def is inside a loop - don’t do that. the def should be immediately following whatever imports the Script needs

import one_thing
import something_else

def sendEmail():
    import system
	recipients=["jane@test.com","jon@xyz.com"] #
	system.report.executeAndDistribute(path="xyz", parameters = {"tankNumber":tankNo}, project="xyz", action= "email", actionSettings = {"to":recipients, "smtpServerName":"Mail Server", "from":"jon@xyz.com", "subject":tank + 'test email', "body":tank + " test "})
			
code()
y = other_code()
for x in y:
    system.util.invokeAsynchronous(sendEmail)
    print 'post-email function'

The def is inside of a for loop, but I don’t see how to prevent this.

The for loop is reading through a SQL table and then taking those tank numbers and searching for tag data. This data is then input into the exectuteAndDistribute function as parameters, so each tag would need a different variable name if not part of the for loop… which I don’t know how it would be sent to the executeAndDistribute command then as parameters.

I tried removing the invokeAsynchronous and still get the same error. Maybe just don’t worry about it now because it seems to be working correctly?

After speaking with a member of Development, it seems like your issue is actually in the Report. updateData is the def given to Report Data Sources which are Scripts.


So look in that script for line 29 (probably the last line). Sorry I directed you to the wrong place - I presumed your encompassing function was named updateData, and I missed the part where you claimed to not know where updateData lived.

Ah, thank you! I knew I had seen it somewhere.

I deleted this Data Source and the error is gone.

-Michael