Our full technical support staff does not monitor this forum. If you need assistance from a member of our staff, please submit your question from the Ask a Question page.

Log in or register to post/reply in the forum.

Optimizing power consumption for battery powered logger and modem (CR300 + COM111)

reinhu Jun 18, 2019 07:04 AM

I have a setup where power consumption is very important, especially in the winter months. Solar panels are not feasible due to low/no light.

The setup is a CR300 with a COM111 3G modem connected through RS232 port and SW12. Attached to the logger is an SDI12 sensor, which is powered by a separate battery (i.e. not through the logger or the same power source).

The SDI12 sensor is scanned at a high frequency (15s), due to one of the measured variable (velocity) has a high temporal variability that we want to capture, and the system as a whole has a fast response time (therefore also logging average values every 5 minutes). Every 6 hours the logger turns on the modem and sends data via HTTP post. To do so it reads the unsent data from the main table, constructs a string (datap) and sends the data via an HTTPPost() call to a datahost. The modem connectivity has some delays and retries, as it often fails to connect. This might be due to bad code on my part on how the modem and PPP is started - so any input on improving this would be greatly appreciated (the modem actually has a connection and IP - this is confirmed by connecting directly to the modem with USB cable, but the PPP dialing fails so the logger does not get an IP).

The modem currently stays on for 10 minutes every time it turns on - this is to leave time for us to connect to it manually in case of need to reprogram or download the datatables via loggernet. Inbetween this the PPP and SW12 is off (to save power) - are there other things I can turn off in order to reduce power consumption?

In general I'm looking for ways to improve the program to optimize power consumption without the obvious of reducing scan rate (15s) or data transmission rate (6 hours). Also memory usuage are important, as the "datap" string can grow very large if the logger fails to connect for a few cycles. Is there a way to check the maximum size I can preallocate to "datap" without running into risks of out of memory errors?

As you can probably see from the code I don't have a lot of experience in CRBasic, and might have overcomplicated things abit. I would really appreciate all kind of feeback to improve this program!


 Program code:

'CR300 Series

' Declare constants
Const NTP_Server = "pool.ntp.org"
Const UTC_Offset = +2 
Const N = 60   ' Station Latitude
Const E = 18 ' Station Longitude
Const Al = 10	' Station Elevation above sea-level

' Declare variables for data pushing
Public sc_site_id As String * 12 
Public http_header As String * 10
Public http_post_response As String * 200
Public flag_return As String * 20
Public http_response_str_split(3) As String * 50
Public http_response_str_error_split(2) As String * 20
Public http_response_str_reporting_split(4) As String * 20
Public http_post_tx

Public i As Long ' Index counter

Public timerecordsend(2) As String * 19 

Public Rec As Long
Public LRecSent As Long = -1 
Public LRecSent_tmp As Long = -1 
Public RecBack As Long 

Const GRDataMaxLen = 60 
Public GRData As String * GRDataMaxLen 

Public headerp As String * 50 
Public datap As String * 7000 
Public max_rows_to_send = 120 ' Number of data rows that will fit into datap length
Public ind_last_row_to_send As Long = 1

Public ReportingInterval As Long

' Modem connection
Const Modemport = COMRS232
Const Modembaud = 115200
Public timetogooff As Boolean
Public retried_http_post As Boolean

' Power management
Public SW12State As Boolean
Public P3Open As String * 15
Public P3Close As String * 15

'Declare Variables and Units
Public BattV
Public PTemp_C
Public SDI12(4)
Public Counter_avg 

Alias SDI12(1)=Depth
Alias SDI12(2)=Velocity
Alias SDI12(3)=Temperature
Alias SDI12(4)=Battery_SF

Alias timerecordsend(1)=TimeRecordSendStr

Units BattV=Volts
Units PTemp_C=Deg C
Units Depth=m
Units Velocity=m/s
Units Temperature=Deg C
Units Battery_SF=Volts
Units Counter_avg=Count

' Define Data Tables
  Average(1,Depth,FP2,Depth = NaN)
  Average(1,Velocity,FP2,Velocity = NaN)
  Average(1,Temperature,FP2,Temperature = NaN)
  Totalize(1, Counter_avg, FP2, False)
  Sample(1,BattV, FP2)


DataTable (ComsLog,True,-1)
  Sample (1,TimeRecordSendStr,String)
  Sample (1,Rec,FP2)
  Sample (1,LRecSent,FP2)
  Sample (1,RecBack,FP2)
  Sample (1,flag_return, String)
  Sample (1,retried_http_post, Boolean)
  Sample (1,ind_last_row_to_send, Long)

'Main Program

  ' On boot
  Counter_avg = 1 
  sc_site_id = "CR300_"+Status.SerialNumber  ' Set a unique site ID based on the logger model and serial number
  flag_return="false"  ' Default to no transmission error
  http_header = ""
  ReportingInterval = 60*60*6  ' 6 hours in seconds

  retried_http_post = false 'set default to false for retried sending data flag.
  ind_last_row_to_send = 1 ' Last data row to send, as counted backwards from last record in table

  ' Sync Clock on boot, need to connect
  P3Open = PPPOpen 'Start PPP
  Delay(1,30,sec) 'Allow 30 seconds for the modem to power on and connect
  NetworkTimeProtocol (NTP_Server,UTC_Offset*3600,1000) 
  Delay(1,10,sec) ' Turn off after 10 more seconds
  SerialOpen (Modemport,Modembaud,0,0,100)
  SerialOut (Modemport,"+++","OK"+CHR(13),1,150)
  SerialOut (Modemport,"AT+CFUN=0"+CHR(13),"OK"+CHR(13),1,300)
  'Delay to allow deregistration
  Delay (1,3,sec)
  P3Close = PPPClose

  'Main Scan
    'Default CR300 Datalogger Battery Voltage measurement 'BattV'
    'Default CR300 Datalogger Processor Temperature measurement 'PTemp_C'

    If SDI12(1)=NaN Then
      Counter_avg = 0
      Counter_avg = 1
      ' Make floating point in expected magnitude for Temp and Battery 
	  ' These two lines can be skipped if they consume alot of power
      SDI12(3) = SDI12(3) * 0.01
      SDI12(4) = SDI12(4) * 0.01

    'Call Data Tables and Store Data
    CallTable Table1
    CallTable Table2


  ' Slow Sequence for data transmission

  ' Turn on modem
  'Run once a (1) minute so can have one minute resolution of timing
  ' Can be set less often to improve battery????
  Scan (1,Min,3,0)
    'Every time ReportingInterval happens turn on the modem

    If TimeIntoInterval (0,ReportingInterval,sec) Then
      P3Open = PPPOpen 'Start PPP
      Delay(1,5,sec) 'Allow 5 seconds for the modem to power on

    ' Tries to turn of modem after 5 minutes if the comport is not active
	' Else turn it off anyway after 10 minutes
    If TimeIntoInterval (300,ReportingInterval,sec) Then timetogooff=true 

    If (timetogooff AND (NOT ComPortIsActive(ComRS232))) OR TimeIntoInterval(600,ReportingInterval,sec) Then
      SerialOpen (Modemport,Modembaud,0,0,100)
      SerialOut (Modemport,"+++","OK"+CHR(13),1,150)
      SerialOut (Modemport,"AT+CFUN=0"+CHR(13),"OK"+CHR(13),1,300)
      'Delay to allow deregistration
      Delay (1,3,sec)
      P3Close = PPPClose
      'Set SW12 port to off


	' Construct and post the data
    If TimeIntoInterval (0,ReportingInterval,sec) Then
      Delay(1,90,sec) '1.5 minute after modem and PPP is on to increase chance of connectivity

      retried_http_post = false ' reset retried flag
      Rec = Table1.Record 'get number of last record in table
      If Rec < LRecSent Then LRecSent = -1 'What if LRecSent is preserved but datatable has been reset? Reset LRecSent.
	  RecBack = Rec - LRecSent 'determine how much need to catch up

      ' Check if RecBack is too long, if its too Long reduce it to the max limit
      If RecBack > max_rows_to_send Then 
        ind_last_row_to_send = RecBack - max_rows_to_send
        RecBack = max_rows_to_send
          ind_last_row_to_send = 1
          'RecBack stays the same

      If RecBack > 0 Then 'If recback is greater than zero then we have records to send

        flag_return = "true" ' default to error state unless transmission succeeds below
        SplitStr(timerecordsend(), Public.Timestamp(4,1), ".",2,7)
        headerp =sc_site_id+","+timerecordsend(1)+","+Table1.Record(1,1)+","+N+","+E+","+Al+CHR(13)+CHR(10) ' build the packet header
		LRecSent_tmp = RecBack + LRecSent ' To not sure new LRecSent until data is actually sent

        For i = ind_last_row_to_send To RecBack ' Loop over rows in GRData
          GetRecord(GRData,Table1,i) 'extract data from data table GetRecord( Dest, TableName, RecsBack )

          GRData = Left (GRData,InStr (2,GRData,"""",2)) & Mid (GRData,InStr (2,GRData,"""",2) + 1,1000) ' redundant?
          GRData = Replace (GRData,"""","") 
          datap=datap + GRData 

        Next i

        ' attempt to post data
        http_post_tx = HTTPPost (, headerp+datap, http_post_response, http_header)

        ' The http_post_response gets split-up into its individual fields
        SplitStr (http_response_str_split(),http_post_response,",",3,7)
        SplitStr (http_response_str_error_split(),http_response_str_split(1),":",2,7)
        SplitStr (http_response_str_reporting_split(),http_response_str_split(2),":",4,7)

        flag_return=http_response_str_error_split(2) ' returns "false" if no error, as string

        ' If not successfull, retry one more time by: disconnect modem, stopping PPP, cutting SW12. Waiting 10 seconds. Start PPP, Start SW12, Wait 90 seconds, send again
        If NOT (flag_return = "false") Then ' In case of error with HTTPPost retry by rebooting modem
          ' Can this be a function/method? possible to gain on power usuage?
          SerialOpen (Modemport,Modembaud,0,0,100)
          SerialOut (Modemport,"+++","OK"+CHR(13),1,150)
          SerialOut (Modemport,"AT+CFUN=0"+CHR(13),"OK"+CHR(13),1,300)
          'Delay to allow deregistration
          Delay (1,3,sec)
          P3Close = PPPClose
          ' Wait 10 seconds, restart modem
          P3Open = PPPOpen 'Start PPP
          SW12(SW12State) 'Boot modem
          ' Wait 90 seconds, try to send again
          http_post_tx = HTTPPost (, headerp+datap, http_post_response, http_header)

          ' The http_post_response gets split-up into its individual fields
          SplitStr (http_response_str_split(),http_post_response,",",3,7)
          SplitStr (http_response_str_error_split(),http_response_str_split(1),":",2,7)
          SplitStr (http_response_str_reporting_split(),http_response_str_split(2),":",4,7)

          flag_return=http_response_str_error_split(2) ' returns false if no error

          retried_http_post = true

        If (flag_return = "false") Then ' If no error, clear the buffers, set the last sent record
          ReportingInterval = http_response_str_reporting_split(4) ' Check for updates in reporting interval from cloud platform
          headerp = ""
          LRecSent = LRecSent_tmp

        datap="" 'always clear

      EndIf 'recback

      ' Sync clock every time the logger connects. Not really necessary, but neglible power consumption??
      NetworkTimeProtocol (NTP_Server,UTC_Offset*3600,1000)  ' Set time to UTC+offset 

      CallTable (ComsLog)

    EndIf ' TimeIntoInterval


reinhu Aug 13, 2019 04:12 AM

Bumping thread - any tips on power optimization using external modem?

Log in or register to post/reply in the forum.