Announcement

Collapse
No announcement yet.

Weeder Devices Script

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Weeder Devices Script

    Dinki asked me to post the scripts I use to work with my various Weeder devices, so here they are.

    It's been a few years since I did this, so my memory may not be the best on specifics.

    I have the following Weeder devices:

    Module A: Analog to Digital (WTADC-M)
    This was originally used to monitor an analog voltage level that was related to a sonar sensor device, so you'll see some code in the ServiceModuleA sub that used to take care of this that is now commented out.

    The other use is to determine if a TV in the house is on. For this TV, I couldn't use a regular current sensing device, because the current level would spike even with the TV off from time to time.

    Of interest to some, might be the low pass filter done in software to smooth out the ADC values coming in from the device.

    Module B: Digital Inputs (WTDIO-M)
    This module has inputs mostly connected to occupancy sensors plus a water meter that closes a contact for every gallon that runs through it. This is to keep track of how much water we're using for summer irrigation. The ServiceModuleB() sub handles this device.


    Module C: Analog Output (WTDAC-M):
    This module is mostly used to control dimmable lighting ballasts that need 0-10 VDC. There is a ServiceModuleC() sub but it really does nothing at this time since I don't really care what I get back from this particular module as it is an output type of module.

    General Logic Flow:
    The Startup.txt calls WeederCB.vb to initialize script level variables. Once HomeSeer loads this script, the script level variables will be persistent from call to call. Initialization consists of setting up a watchdog to catch if a module gets accidentally disconnected from the system, and seeding the ADC low pass filter used for the ADC module.

    Also, there is a startup script for each module that is run once to set the various features of each module.

    Also, I added the command to open the COM port the weeder devices are stacked on and to tell HomeSeer what script to call when data is received on the port:


    Code:
    'startup.txt code snippet 
     'Weeder script
      'Initilize vars in callback script...
      hs.run "WeederCB.vb"
      strError = HS.OpenComPort(9,"9600,N,8,1",1,"WeederCB.vb","Callback",vbCR)
      IF strError = "" THEN
        HS.WriteLog "Weeder","Weeder interface opened on port COM9"
      ELSE
        HS.WriteLog "Weeder","Weeder interface port error: " & TRIM(strError)
      END IF
    
      'Start Weeder config right away and the polling script 15 secs later...
       hs.Run "WeederStartupModB.vb"
       hs.Run "WeederStartupModC.vb"
       if hs.IsOn("r10") then hs.DelayTrigger 15, "Start Weeder Polling Script"
    Here are the various module startup scripts:

    Code:
    'WeederStartupModB.vb
    'Weeder Technologies RS-232 Stackable Modules Polling Script
    'Last Modified: 2009-01-02
    '
    'Responsible for configuring the Digital I/O Module B for correct operation with HomeSeer
    '
    Sub Main(xParms as Object)
    
      hs.SendToComPort(9,"BX0"+CHR(13))   'Turn off command echo
      hs.WaitSecs(1)
      hs.SendToComPort(9,"BSA"+CHR(13))   'Set port A to be a switch input
      hs.WaitSecs(1)
      hs.SendToComPort(9,"BSC"+CHR(13))   'Set port C to be a switch input
      hs.WaitSecs(1)
      hs.SendToComPort(9,"BSD"+CHR(13))   'Set port D to be a switch input
      hs.WaitSecs(1)
    
      hs.SendToComPort(9,"BBB"+CHR(13))   'Set port B to be a button input
      hs.WaitSecs(1)
      hs.SendToComPort(9,"BTB0"+CHR(13))  'Set port B button input not to repeat
      hs.WaitSecs(1)
      hs.SendToComPort(9,"BRA"+CHR(13))   'Get current status of port A
      hs.WaitSecs(1)
      hs.SendToComPort(9,"BRC"+CHR(13))   'Get current status of port C
      hs.WaitSecs(1)
      hs.SendToComPort(9,"BRD"+CHR(13))   'Get current status of port D
      hs.WaitSecs(1)
    
    End Sub
    Code:
    'WeederStartupModC.vb
    'Weeder Technologies RS-232 Stackable Modules Startup Script For Module C
    'Last Modified: 2009-01-02
    '
    'Responsible for configuring the Analog Output Module C for correct operation with HomeSeer
    '
    Sub Main(xParms as Object)
    
      hs.SendToComPort(9,"CX1"+CHR(13))   'Turn off command echo
      System.Threading.Thread.Sleep(200)
      hs.SendToComPort(9,"CRA255"+CHR(13))   'Set port A ramp-rate
      System.Threading.Thread.Sleep(200)
      hs.SendToComPort(9,"CRB255"+CHR(13))   'Set port B ramp-rate
      System.Threading.Thread.Sleep(200)
    
      hs.SendToComPort(9,"CVA"+CHR(13))   'Get current voltage level of port A
      System.Threading.Thread.Sleep(200)
      hs.SendToComPort(9,"CVB"+CHR(13))   'Get current voltage level of port B
      System.Threading.Thread.Sleep(200)
    
    End Sub

    After that, whenever data is received, the Callback sub located in the WeederCB.vb script file is called. The Callback sub determines which module the data is from, and calls another sub to service data for that particular module.

    Code:
    'WeederCB.vb
    'Weeder Technologies RS-232 Stackable Modules Callback Script
    'Last Modified: 2007-01-30
    'Polling script is Weeder.vb
    'If a change is made to this script while HomeSeer has it active, errors will occur in the log
    'following because the Main() sub will not have been called prior.
    
    Const   LivRmTV              = "s5"
    Const   ScriptStatusDevice   = "r12"
    Const   DnBathRmMotionSensor = "r21"
    Const   CraftRmMotionSensor  = "r22"
    Const   FamRmMotionSensor    = "r23"
    
    Const   IrrigationMeterDevice = "s20"
    
    'Drain-tile lift station constants
    'Const DrainTileHeadroomDevice As String = "r16" 'HS device that holds distance from pipe outlet to water level
    'Enum LiftStation
    '  Empty          = 31    'Distance from sensor to bottom of lift station
    '  PumpOff        = 28    'Distance from sensor when pump turns off (water level settles at 27)
    '  PumpOn         = 24    'Distance from sensor when pump turns on
    '  Alarm          = 19    'Distance from sensor when float sensor alarms
    '  PipeOutlet     = 12    'Distance from sensor to bottom of drain tile pipe outlet
    'End Enum
    
    Const   CallbacksPerMinute = 180    '3 callbacks/second
    'Const   CallbacksPerMinute = 60    '1 callbacks/second
    
    Const   STATUS_Off = 3
    Const   STATUS_On  = 2
    Const   STATUSTEXT_Reporting = "Reporting"
    Const   STATUSTEXT_Fault     = "Fault"
    Const   STATUSTEXT_Running   = "Running"
    
    Structure AdcInput
      Dim RawIn  As Integer 'Raw, unfiltered, ADC input
      Dim FilOut As Integer 'Filtered ADC input
      Dim Acc    As Integer 'Filter Accumulator
      Dim K      As Integer 'Time Constant x Samples/Sec
      Dim Offset As Integer 'Offset adjustment
    End Structure
    
    Structure Watchdog       'One Watchdog per Weeder module
      Dim Timer  As Integer  'Reset to max value on each successful read
      Dim Device As String   'HomeSeer watchdog device code reflecting status of module
    End Structure
    
    'Script level variables
    Dim Inited As Boolean = False   'Indicates if script level vars have been inited in case script gets restarted
    Dim WatchdogCounter As Integer  'Watchdog Counter counts up to CallbacksPerMinute
    Dim Adc1(8)      As AdcInput '8 A-to-D inputs on the Weeder Analog Input Module
    Dim Watchdogs(1) As Watchdog '1 Weeder modules connected so far
    
    Sub Main(xParms as Object)
      InitVars()
    End Sub
    
    'Automatically called by Homeseer whenever
    'data arrives at the port terminated with a CR
    Sub Callback(strData)
      Dim InputValue As String()
      Dim I as Integer
    
      WatchDogCounter += 1
      'Update HomeSeer device approx. once/minute -- Event in HS also decrements this once/min.  If zero, trouble!
      If WatchDogCounter >= CallbacksPerMinute
        WatchDogCounter = 0
        hs.SetDeviceValue(ScriptStatusDevice,3)
      End If
    
      'Make sure global script variables have been initialized
      If Inited <> True Then InitVars()
    
      'Split incoming values into a string array
      InputValue = strData.Split(New [Char]() {" "})
    
      'Strip off first letter of first value as it is the device ID
      InputValue(0) = InputValue(0).Substring(1)
    
      If strData.SubString(1) = "?"
        hs.WriteLog("WeederCB.vb Warning","Invalid command sent to module " & strData.SubString(0,1))
        Exit Sub
      End If
    
      Select Case strData.SubString(0,1)
        Case "A"
          ServiceModuleA(InputValue)
        Case "B"
          ServiceModuleB(InputValue)
        Case "C"
          ServiceModuleC(InputValue)
      End Select
    
      'Decrement watchdog timers
      For I = 1 to UBound(Watchdogs)
        Watchdogs(I).Timer -= 1
        'hs.WriteLog("Weeder","Watchdogs(" & I & ").Timer = " &  Watchdogs(I).Timer)
        If Watchdogs(I).Timer = 0
          SetStatus(Watchdogs(I).Device,STATUSTEXT_Fault)
        End If
      Next
    
    End Sub
    '----------------------------------------------------------------------------------------------------------------------
    Sub ServiceModuleA(InputValue)
      Dim I, iVar1 as Integer
    
      'ADC Input Module A
        'hs.WriteLog("Weeder","Callback (A) with " & TRIM(strData))
        'Reset watchog timer
        If Watchdogs(1).Timer <= 0
          SetStatus(Watchdogs(1).Device,STATUSTEXT_Reporting)
        End If
        Watchdogs(1).Timer = 4
        For I = 1 to 8
          'Process samples
          Adc1(I).RawIn = InputValue(I-1) + Adc1(I).Offset
          If Adc1(I).Acc = 0
            'hs.WriteLog("Weeder","Accumulator " & I & " was zero.")
            Adc1(I).Acc = Adc1(I).K * Adc1(I).RawIn  'On startup, seed the accumulator
          End If
          Adc1(I).FilOut = Adc1(I).Acc \ Adc1(I).K
          Adc1(I).Acc = Adc1(I).Acc + Adc1(I).RawIn - Adc1(I).FilOut
        Next
    
    '    'Monitor drain tile sump sonar sensor
    '    iVar1 = (Adc1(1).FilOut \ 10) - LiftStation.PipeOutlet
    '    If hs.DeviceValue(DrainTileHeadroomDevice) <> iVar1
    '      hs.SetDeviceValue(DrainTileHeadroomDevice,iVar1)
    '      hs.SetDeviceString(DrainTileHeadroomDevice,iVar1 & " in.")
    '    End If
    
    
    
        'Monitor living room TV status
        'hs.WriteLog("Weeder","Adc1(2).FilOut=" & Adc1(2).FilOut)
        If Adc1(2).FilOut > 50 AND hs.DeviceStatus(LivRmTV) <> STATUS_On
          hs.SetDeviceStatus(LivRmTV,STATUS_On)
        ElseIf Adc1(2).FilOut < 20 AND hs.DeviceStatus(LivRmTV) <> STATUS_Off
          hs.SetDeviceStatus(LivRmTV,STATUS_Off)
        End If
    
    
    
    End Sub
    
    '----------------------------------------------------------------------------------------------------------------------
    Sub ServiceModuleB(InputValue)
      Dim I as Integer
      Dim Cmd as String
    
      'hs.WriteLog("WeederCB.vb","Callback (B)")
      'For I = 0 To UBOund(InputValue)
      '  hs.WriteLog("WeederCB.vb"," Module B Element " & I & " = " & InputValue(I))
      'Next
    
      Cmd = InputValue(0).Substring(1)  'This holds the received command/status
      Select Case InputValue(0).Substring(0,1) 'This holds the I/O Letter
        Case "A"        'FamRm Occupancy Sensor
          If Cmd = "H"  'Indicating no occupancy
            hs.SetDeviceStatus(FamRmMotionSensor,STATUS_Off)
          Else
            hs.SetDeviceStatus(FamRmMotionSensor,STATUS_On)
          End If
    
    
        Case "B"
          If Cmd = "L"  'Indicating button pushed (1 per gallon)
            hs.SetDeviceValue(IrrigationMeterDevice,hs.DeviceValue(IrrigationMeterDevice) + 1)
            hs.SetDeviceString(IrrigationMeterDevice,hs.DeviceValue(IrrigationMeterDevice) & " Gal.")
          End If
    
        Case "C"
          If Cmd = "H"  'Indicating no occupancy
            hs.SetDeviceStatus(CraftRmMotionSensor,STATUS_Off)
          Else
            hs.SetDeviceStatus(CraftRmMotionSensor,STATUS_On)
          End If
    
        Case "D"
          If Cmd = "H"  'Indicating no occupancy
            hs.SetDeviceStatus(DnBathRmMotionSensor,STATUS_Off)
          Else
            hs.SetDeviceStatus(DnBathRmMotionSensor,STATUS_On)
          End If
    
        Case "E"
        Case "F"
        Case "G"
        Case "H"
        Case "I"
        Case "J"
        Case "K"
        Case "L"
        Case "M"
        Case "N"
    
      End Select
    
    End Sub
    
    
    '----------------------------------------------------------------------------------------------------------------------
    Sub ServiceModuleC(InputValue)
      Dim I as Integer
      Dim Cmd as String
    
      hs.WriteLog("WeederCB.vb","Callback (C)")
      For I = 0 To UBOund(InputValue)
        hs.WriteLog("WeederCB.vb"," Module C Element " & I & " = " & InputValue(I))
      Next
    
      Cmd = InputValue(0).Substring(1)  'This holds the received command/status
    
    End Sub
    
    '----------------------------------------------------------------------------------------------------------------------
    Sub SetStatus(Device As String, StatusText As String)
      hs.SetDeviceString(Device,StatusText)
    
      If StatusText = STATUSTEXT_Reporting
        hs.SetDeviceStatus(Device,STATUS_On)
      Else
        hs.SetDeviceStatus(Device,STATUS_Off)
      End If
    
    End Sub
    
    'Initializes script level variables for use by callback function.
    'Called via startup.txt on HS startup and whenever script is recompiled.
    Sub InitVars()
    Dim I As Integer
    
      Inited = True
    
      'Seed the HS callback script watchdog timer to prevent startup errors...
      hs.SetDeviceValue(ScriptStatusDevice,3)
    
      'Init watchdog device names
      '  ADC Module 1
      Watchdogs(1).Timer  = 4
      Watchdogs(1).Device = "r15"
    
      For I = 1 to UBound(Watchdogs)
        SetStatus(WatchDogs(I).Device,STATUSTEXT_Reporting)
      Next
    
      'All inputs can be digitally filtered using a software based low-pass filter.
      'K = Samples/Sec * Desired Time Constant (3 samples/sec * 5 secs = K of 15)
      'Currently, the device is polled about 3 times/sec.
      'Initialize Time Constant K and Offset for each input
    
      'Input 1 is drain tile sump sonar reading
      Adc1(1).K = 90        '2 second time constant  (3*3)
      Adc1(1).Offset = -3
    
      'Input 2 is living room TV
      Adc1(2).K = 6
    
      'All inputs require a K value
      Adc1(3).K = 3
      Adc1(4).K = 3
      Adc1(5).K = 3
      Adc1(6).K = 3
      Adc1(7).K = 3
      Adc1(8).K = 3
    
    End Sub
    Finally, there is a polling script that is responsible for asking the ADC module for values about 3 times per second. Of course, those values are returned in the WeederCB.vb script that is receiving all output from the modules as discussed earlier. It has a few subs in it to set the dim levels for the dimmable ballasts.

    Code:
    'Weeder.vb
    'Weeder Technologies RS-232 Stackable Modules Polling Script
    'Last Modified: 2006-05-20
    '
    'Data received from the devices is processed by WeederCB.vb
    
    Const WeederPollingScriptDevice = "R10"
    Const   STATUS_On  = 2
    
    'Script entry point, called once when HomeSeer starts up.
    SUB Main(xParms as Object)
      DO
        hs.WaitEvents()
    
        If hs.DeviceStatus(WeederPollingScriptDevice) = STATUS_On
          hs.SendToComPort(9,"AS"+CHR(13)) 'Return all single-ended values from ADC module addressed as "A"
        End If
    
        'goto sleep for just under a 1/3 of a second; should allow polling rate
        'of 3 samples/second by the time WaitEvents() runs, etc.
        System.Threading.Thread.Sleep(300)
    '    System.Threading.Thread.Sleep(1000)
      LOOP
    
    END SUB
    
    SUB SendToModule(xMsg as String)
          hs.SendToComPort(9,xMsg+CHR(13))
    
    
    
    '  Select Case xMsg.SubString(0,1)
    '    Case "C"
    '      ModuleC(xMsg)
    '  End Select
    
    
    
    
    
    END SUB
    
    
    Sub SetDimLevel(xDeviceID As String)
    
      hs.SendToComPort(9,"CTA" & hs.DeviceValue(xDeviceID) & CHR(13))
    
    End Sub
    
    Sub RaiseDimLevel(xDeviceID As String)
      Dim DimLevel As Integer
      DimLevel = hs.DeviceValue(xDeviceID)
      If DimLevel <= 900
        hs.SetDeviceValue(xDeviceID,DimLevel + 100)
        'hs.WriteLog("Weeder.vb","Raised dim level on " & xDeviceID & " to " & hs.DeviceValue(xDeviceID))
      End If
    
    End Sub
    
    Sub LowerDimLevel(xDeviceID As String)
      Dim DimLevel As Integer
      DimLevel = hs.DeviceValue(xDeviceID)
      If DimLevel >= 300
        hs.SetDeviceValue(xDeviceID,DimLevel - 100)
        'hs.WriteLog("Weeder.vb","Lowered dim level on " & xDeviceID & " to " & hs.DeviceValue(xDeviceID))
      End If
    
    End Sub
    If you're just trying to work with digital input module, all you really need is some of the code from the WeederCB.vb script, specifically the stuff in ServiceModuleB()...

    I'm sure I've left a few things out, but maybe this would be a springboard for you to get started and ask some more questions...

    #2
    Thanks for posting. This looks very promising for my needs.

    Comment

    Working...
    X