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:
Here are the various module startup scripts:
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.
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.
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...
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"
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
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
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...
Comment