by Gary Roberts | Updated: 05/31/2017 | Comments: 2
Maybe you’re like me when it comes to skipped scans. I have always disliked seeing skipped scans in my data loggers. I have been trained to watch out for them and do my best to write my CRBasic programs in a way that makes them not appear. The Campbell Scientific Support and Implementation Engineers (formally known as Application Engineers or AEs) tell me that skipped scans are a sign of trouble in my system. When I see them, something is amiss, and I need to do some maintenance on my station before I lose too much of my data.
Skipped scans, when used this way, are a good thing, right? They let us know that something is wrong.
Skipped scans sometimes tell us that we have an SDI-12 sensor that is no longer responding correctly or in the amount of time that we expected it to. Skipped scans can also tell us that some TCP/IP functions, such as EmailSend() or FTPClient(), are taking too long or are not working as they should be. That is great diagnostic information for us to use. (Read the "Tips and Tricks: Skip Skip Hooray [Not]" article for more information.)
The main scan, and each slow sequence (up to four in a CRBasic program), has a record in the Status table showing how many times the data logger was unable to complete a scan. The row named SkippedScan in the Status table tells us how many times the main scan was not fully completed. The SkippedSlowScan(x) rows tells us the same thing for each slow scan (“x” being the number of the slow scan it is associated with).
SkippedScan | 0 |
SkippedSystemScan | 0 |
SkippedSlowScan(1) | 0 |
SkippedSlowScan(2) | 0 |
SkippedSlowScan(3) | 0 |
So, as a station or system operator, keeping track of skipped scans can be very beneficial.
There are ways that we can programmatically keep these vital statistics clean while still having the data logger do what it needs to do without it giving a false skipped scan.
What do I mean by that? Let me give you an example.
Recently, Campbell Scientific added a new function called EMailRelay(). (You can learn more about it in the “Sending Email from Your Data Logger Just Got Easier” blog article.) It gives you the ability to send an email or text message to your users without having to go through all the headache of setting up email accounts or working with your IT staff to get access to the office email system. It is a great little function that helps you send out alerts quickly.
Campbell Scientific Support and Implementation Engineers recommend that CRBasic programmers add this function into one of the slow sequences in their programs. Why? Because there are times (depending on network speed, server load, etc.) that the EmailRelay() function might take longer to run than was originally expected. Maybe longer than the slow sequence’s scan interval. When it does run longer, it might hang up long enough that the scan it is in runs into the next scan interval, causing the data logger to log a skipped scan.
Is this something that we need to be bothered with? In this case, if EmailRelay() is the only function running in the slow sequence, no. Nothing was messed up. The data logger could send the alert it needed to. It just took longer than expected to send it.
We will still get a skipped scan. In LoggerNet, it will show up in red in the Station Status of the Connect screen. (Watch the "Connect Window Tutorial" for more information.) It is going to annoy us and want us to do something about it. In this case, there is nothing neither we nor the data logger can fix that we have control over.
So how do we get around this? We don’t want to be presented with skipped scans when there isn’t an error that we need to deal with. How do we only see skipped scans in the Status table when there really is something going wrong with our system?
This is where a Do/Loop instruction instead of a Scan/NextScan in a slow sequence is very helpful.
For example, we may have a simple CRBasic program using EmailRelay() that looks something like this:
'Main program variables Public battery_voltage Public panel_temperature Public temperature 'EmailRelay() constants Const _EMAIL_ATTACHMENT = "" Const _EMAIL_SUBJECT = "Email Message" Const _EMAIL_TO_ADDRESS = "some.user@campbellsci.com" Const _CR_LF = CHR(13) & CHR(10) 'EmailRelay() variables Public email_message As String * 300 Public email_relay_server_response As String * 100 Public email_trigger As Boolean Public email_tx_success BeginProg Scan (1,Sec,3,0) Battery (battery_voltage) PanelTemp (panel_temperature,250) TCDiff (temperature,1,mV2_5C,1,TypeT,panel_temperature,True ,0,250,1.0,0) If temperature > 30 Then email_trigger = True EndIf NextScan SlowSequence Scan(1,sec,1,0) If email_trigger = True Then email_trigger = False 'reset my trigger email_message = "Warning!" & _CR_LF & _CR_LF email_message = email_message & "This is a automatic email message from the datalogger station " & Status.StationName & ". " email_message = email_message & "An alarm condition has been identified." & _CR_LF email_message = email_message & "The temperature is " & temperature & " degrees C." & _CR_LF email_message = email_message & "Datalogger time is " & Status.Timestamp email_tx_success = EmailRelay (_EMAIL_TO_ADDRESS,_EMAIL_SUBJECT,email_message,email_relay_server_response,_EMAIL_ATTACHMENT) EndIf NextScan EndProg
When this program is running and the temperature gets higher than 30 degrees Celsius, the data logger trips the alarm by setting the email_trigger variable to True. In the slow sequence, which is running a scan of every second, the EmailRelay() instruction runs. EmailRelay() definitely will take longer than one second to send the email message. In fact, it could take up to 70 seconds if the data logger cannot talk to the EmailRelay server. In either case, the data logger will record skipped scans for the first slow sequence regardless of whether EmailRelay() is successful or not.
So let’s put EmailRelay() into a Do/Loop instead and use CRBasic to tell us when EmailRelay() did not work:
'Main program variables Public battery_voltage Public panel_temperature Public temperature 'EmailRelay() constants Const _EMAIL_ATTACHMENT = "" Const _EMAIL_SUBJECT = "Email Message" Const _EMAIL_TO_ADDRESS = "some.user@campbellsci.com" Const _CR_LF = CHR(13) & CHR(10) 'EmailRelay() variables Public email_message As String * 300 Public email_relay_server_response As String * 100 Public email_relay_results_human_readable As String * 100 Public email_trigger As Boolean Public email_tx_success BeginProg Scan (1,Sec,3,0) Battery (battery_voltage) PanelTemp (panel_temperature,250) TCDiff (temperature,1,mV200C,U1,TypeT,panel_temperature,True ,0,250,1.0,0) If temperature > 30 Then email_trigger = True EndIf NextScan SlowSequence Do If email_trigger = True Then email_trigger = False 'reset my trigger email_message = "Warning!" & _CR_LF & _CR_LF email_message = email_message & "This is a automatic email message from the datalogger station " & Status.StationName & ". " email_message = email_message & "An alarm condition has been identified." & _CR_LF email_message = email_message & "The temperature is " & temperature & " degrees C." & _CR_LF email_message = email_message & "Datalogger time is " & Status.Timestamp '1st attempt email_tx_success = EmailRelay (_EMAILTO_ADDRESS,_EMAIL_SUBJECT,email_message,email_relay_server_response,_EMAIL_ATTACHMENT) 'If EmailRelay was not successful, let us try one more time. If email_tx_success <> -1 Then '2nd attempt email_tx_success = EmailRelay (_EMAIL_TO_ADDRESS,_EMAIL_SUBJECT,email_message,email_relay_server_response,_EMAIL_ATTACHMENT) EndIf 'tell my human what happened with EmailRelay in human speak instead of loggerspeak ' my user got this information from the CRBasic help for EmailRelay Select Case email_tx_success Case -1 email_relay_results_human_readable = "EmailRelay server received the message from the datalogger successfully!" Case 0 email_relay_results_human_readable = "The connection to the EmailRelay server failed." Case -2 email_relay_results_human_readable = "Execution of the EmailRelay function did not occur due to lack of records or not enough time." Case -3 email_relay_results_human_readable = "A connection to the EmailRelay server was made but there was an error in communication." EndSelect EndIf Loop EndProg
By putting EmailRelay() in a Do/Loop instead of a Scan/NextScan, the Do/Loop runs constantly until email_trigger becomes set to True. When it does, the CRBasic code between the If Then and EndIf statements gets executed.
If EmailRelay() takes 10 seconds to do its job or 70 seconds to finish, the data logger does not record a skipped scan. So now we avoid seeing red in LoggerNet’s Connect screen!
How will we know if the data logger is having trouble sending emails using EmailRelay()? We can look at the value that EmailRelay() returns to the data logger, as well as the troubleshooting variables in the function itself.
In our example program, we can create a variable called email_tx_success that we and the data logger can use to determine success and failure.
email_tx_success = EmailRelay (…
When EmailRelay() is executed, it returns a value to email_tx_success depending on what happened. The details can be found in CRBasic’s Help or in the Case statements added to the CRBasic program in this example.
We can also look at the variable email_relay_server_response to get more details if we need to. This variable contains the information returned to the data logger by the EmailRelay() server. Upon successful communication with the server, email_relay_server_response may contain something like this:
{"messagetype":"acknowledgement","message":"email-sent"}
This response is in JSON format and could easily be parsed by the data logger if we needed to do something with it and have the data logger act upon it.
In our example, here’s how the data logger could retry sending a failed message depending on the response it received with its first attempt:
'If EmailRelay was not successful, let us try one more time. If (email_tx_success <> -1) Then '2nd attempt email_tx_success = EmailRelay (_EMAIL_TO_ADDRESS,_EMAIL_SUBJECT,email_message,email_relay_server_response,_EMAIL_ATTACHMENT) EndIf
It is a simple example that you can expand on if you need to.
Do/Loops in slow sequences are a great way to avoid seeing skipped scans in your data logger. I hope you find these examples useful. You can download the original EmailRelay() example, as well as the Do/Loop EmailRelay() example.
Are there other ways you program your data loggers to avoid unnecessary skipped scans? If so, please share below.
Comments
minida28 | 04/18/2020 at 01:33 AM
Hi Gary,
Thanks for this post, I am new with Campbell system so this blog post is really helpful for me to understand how the code blocks are executed within CRBasic programming.
But I have question, with the Do/Loop runs infinetely like your code above and the code is executed outside the scan section, will the datalogger ever go into quiescent mode?
Thanks,
miq
GaryTRoberts | 04/20/2020 at 10:57 AM
MIQ,
Good catch. You are correct. The datalogger will not go into quiescent mode using the do loop as writtin. To allow the datalogger to go in to quiescent mode, a Delay will need to be added to the Do/Loop. Users could all use a WaitTriggerSequence/TriggerSequence to control the use of the Do/Loop.
Please log in or register to comment.