for (x =1;x<41;x++)
{
[dvTP,nTPbuttons[x]] = nLiteStatus[nTPbuttons[x]]
}
and the case statements can be stacked...
switch (message))
{
case 'E001':
case 'E002':
case 'E003':
case 'E004':
case 'E005':
case 'E006':
case 'E007':
case 'E008':
case 'E009':
case 'E010':
{
on[dvDevice,nReady]
}
}
Also I would use channels on the Virtual or Actual device as much as possible. This give access to what is going on with this control system to other AMC control systems. If your just changing a variable from 0 to 1, that information is only accessible by the local controller.
switch (message))
{
case 'E001':
case 'E002':
case 'E003':
case 'E004':
case 'E005':
case 'E006':
case 'E007':
case 'E008':
case 'E009':
case 'E010':
{
on[dvDevice,nReady]
}
}
Also I would use channels on the Virtual or Actual device as much as possible. This give access to what is going on with this control system to other AMC control systems. If your just changing a variable from 0 to 1, that information is only accessible by the local controller.
wouldn't it be great if you could do some kind of array for a stacked case...
switch (message))
{
case cCase_Array:
{
on[dvDevice,nReady]
}
}
Also, be careful using a FOR loop in DEFINE_PROGRAM, it's a huge process hog. If you wind up seeing a performance hit, you can easily let the load off by surrounding your FOR loop with a WAIT 2 . . . your eye is not going to notice a 2/10 of a second delay in updating feedback.
I'd like to see you get rid of the WAIT_UNTILs in the button_events and put that code in the string_event handler under a switch case for cType or cLstCmdSent or something.
You then might consider creating a queue so you only send commands after a response from the previous command is received. Put in a time out period via a wait in case a valid response isn't received in a resonable amount of time so you can send the next string in queue. The way the code is now you could possible keep pushing buttons and sending strings before getting any replies back and being nReady. Some devices don't like that. You could also block further button pushes if nReady isn't ready but that might piss off the user so you're better off using a queue.
Also, be careful using a FOR loop in DEFINE_PROGRAM, it's a huge process hog. If you wind up seeing a performance hit, you can easily let the load off by surrounding your FOR loop with a WAIT 2 . . . your eye is not going to notice a 2/10 of a second delay in updating feedback.
Not too sure if there is that much difference in processing. Everytime mainline is processed 40 loops of the FOR loop is processed with 1 line of feedback per loop. OR 40 lines of Feedback in each loop of mainline. Seems like a wash to me... Just a lot of less typing with the FOR loop. Also virtual devices start at 33001.
Ok so here is what I am thinking if I add ",UP" to the end of the command I will get the status of the light as shown below
>N8OF,UP - Turn light node 8 Off, and requests an update.
<E000 - Acknowledges the command
<X000 - RF Transmission was sent successfully (X002 means unsuccessfully)
<N008L000 - Returns the status of the light node
If I do not put the ",UP" on the command I would only get this:
>N8OF,UP - Turn light node 8 Off, and requests an update.
<E000 - Acknowledges the command
<X000 - RF Transmission was sent successfully
I also found out that the "X000 or X002" means that I can send another command so that is where I should set the nReady state and not on the other feedback messages.
kbeattyAMX
and the case statements can be stacked...
Not too sure if there is that much difference in processing. Everytime mainline is processed 40 loops of the FOR loop is processed with 1 line of feedback per loop. OR 40 lines of Feedback in each loop of mainline. Seems like a wash to me... Just a lot of less typing with the FOR loop. Also virtual devices start at 33001
I have not done anything with the Error codes yet not sure if I will do anything with them or not
I have them defined the virtual devices but have not used them yet I may get rid of them and I corrected the addressing for now.
ericmedley
wouldn't it be great if you could do some kind of array for a stacked case...
Not sure if you are being sarcastic or not but yest that would be great, is this allowed?
Not a 100% what this is actually performing. nReady is just a flag that I am using to make sure that the device is ready to receive another command.
vining
I'd like to see you get rid of the WAIT_UNTILs in the button_events and put that code in the string_event handler under a switch case for cType or cLstCmdSent or something
I would love to use a buffer to send the commands I just need to figure out how.
Also if there is a change of status to any light that is done by the light switch itself the level info would be sent to the Netlinx so would I really need the feedback in the DEFINE_PROGRAM section?
Not too sure if there is that much difference in processing. Everytime mainline is processed 40 loops of the FOR loop is processed with 1 line of feedback per loop. OR 40 lines of Feedback in each loop of mainline. Seems like a wash to me... Just a lot of less typing with the FOR loop. Also virtual devices start at 33001.
Hey - don't get me wrong, it's helpful and yes - I do FOR loops in DEFINE_PROGRAM. I've a couple of programs where the FOR loop crippled the system . . . breaking it up with a WAIT or removing some of it and doing direct feedback helped. And I should mention, these were larger systems (18 touch panels in one job, with lighting feedback.)
I'm not much of a benchmark guy, but if anyone has any numbers that'd be great. I heard numbers before in Programmer 3 - but to be honest, forgot them.
For feedback, I typically run a repeating timeline_event at a 1/10 of a second and if feedback is sequential arrays of stuff, I'd condense it down to a for loop. Less critical feedback would run in a repeating timeline_event at 1/2 to 1/3 of a second. I normally don't put stuff like this in mainline but if it is a small program like a typical conference room, its easy just to do feedback there.
Ok I made some changes, I am trying the command queue and also the For loop that was mentioned. In the queue portion I put the nReady change in the DATA_EVENT because the lights will reject a command until I receive a X000, X002, or an Exxx error code. I hope I did the queue correctly. Also when I compile this code I get several of these warnings:
C10571: Converting type [string] to [CHAR] - should I be worried about these, is there a way to correct the problem? I saw a tech note on how to disable the warnings but do they affect anything?
PROGRAM_NAME='Client XXX'
(***********************************************************)
(***********************************************************)
(* FILE_LAST_MODIFIED_ON: 11/07/2008 AT: 10:07:19 *)
(***********************************************************)
(* System Type : NetLinx *)
(***********************************************************)
(* REV HISTORY: *)
(***********************************************************)
(*
$History: $
*)
(***********************************************************)
(* DEVICE NUMBER DEFINITIONS GO BELOW *)
(***********************************************************)
DEFINE_DEVICE
dvTP = 128:1:0
dvViziaRF = 5001:1:0
(* Buad = 9600
data bits = 8
stop bit = 1
parity = no parity
Handshaking = off *)
vdvTP = 33001:1:0
vdvViziaRF = 33002:1:0
(***********************************************************)
(* CONSTANT DEFINITIONS GO BELOW *)
(***********************************************************)
DEFINE_CONSTANT
INTEGER nTPButtons[] =
{
// Individual Nodes
101, //Node 1
102, //Node 2
103, //Node 3
104, //Node 4
105, //Node 5
106, //Node 6
107, //Node 7
108, //Node 8
109, //Node 9
110, //Node 10
111, //Node 11
112, //Node 12
113, //Node 13
114, //Node 14
115, //Node 15
116, //Node 16
117, //Node 17
118, //Node 18
119, //Node 19
120, //Node 20
// Groups - A set of switches/Dimmers to behave as one node
201, //Group 1
202, //Group 2
203, //Group 3
204, //Group 4
205, //Group 5
206, //Group 6
207, //Group 7
208, //Group 8
209, //Group 9
210, //Group 10
//Scenes
301, //Scene 1
302, //Scene 2
303, //Scene 3
304, //Scene 4
305, //Scene 5
306, //Scene 6
307, //Scene 7
308, //Scene 8
309, //Scene 9
310 //Scene 10
}
(***********************************************************)
(* VARIABLE DEFINITIONS GO BELOW *)
(***********************************************************)
DEFINE_VARIABLE
VOLATILE CHAR cType //Stores Selected Node Type
VOLATILE CHAR cTypeData //Stores the type of device on feedback
VOLATILE CHAR cNode //Stores Selected Light Node
VOLATILE CHAR cGroup //Stores Selected Light Group
VOLATILE CHAR cScene //Stores Selected Light Scene
VOLATILE CHAR cStatus //Stores Status of Selected Light Zone
VOLATILE CHAR cMessage //Stores Light Node/Group/Scene Level error information
Char cViziaRFQue[255]
INTEGER nReady //Flag for waiting for response from Lights
INTEGER nLiteStatus[400] //Stores Light Status for feedback on TP
INTEGER nNode //Stores Selected Light Node for Array position
INTEGER nGroup //Stores Selected Light Group for Array position
INTEGER nScene //Stores Selected Light Scene for Array position
INTEGER nType //Stores Selected Light Type for Array Position
INTEGER x //COunt in For Loop for feedback
(***********************************************************)
(* Function/Calls Code Goes Here *)
(***********************************************************)
Define_Function SendViziaRFQue ()
{
Local_Var Char cCmd[50]
If(![dvViziaRF,nReady] && Length_String(cViziaRFQue))
{
cCmd = Remove_String(cViziaRFQue,"13",1)
Send_String dvViziaRF,"cCmd"
Send_String 0,"'Sent Leviton Command: ',cCmd"
}
}
Define_Function AddtoViziaRFQue (Char cCmd[50])
{
cViziaRFQue = "cViziaRFQue,cCmd,13"
Send_String 0,"'Added Leviton Command: ',cCmd"
}
(***********************************************************)
(* STARTUP CODE GOES BELOW *)
(***********************************************************)
DEFINE_START
(***********************************************************)
(* THE EVENTS GO BELOW *)
(***********************************************************)
DEFINE_EVENT
BUTTON_EVENT [dvTP, nTPButtons]
{
PUSH:
{
STACK_VAR INTEGER nButtonIndex
nButtonIndex = GET_LAST(nTPButtons)
nType = nButtonIndex
IF (nType < 200)
{
cType = 'Node'
Send_String 0,"cType"
cNode = ITOA(nButtonIndex)
AddtoViziaRFQue ("'>?N',cNode") //gets the status of the Light Zone
IF (cStatus = 'OF')
{
AddtoViziaRFQue ("'>N',cNode,'ON,UP'") //Turn Light Zone On
}
ELSE
{
AddtoViziaRFQue ("'>N',cNode,'OF,UP'") //Turn Light Zone Off
}
}
ELSE IF (nType < 300)
{
cType = 'Group'
Send_String 0,"cType"
cGroup = ITOA(nButtonIndex)
AddtoViziaRFQue ("'>?GR',cGroup") //Gets the status of the Light Group
IF (cStatus = 'OF')
{
AddtoViziaRFQue ("'>GR',cGroup,'ON,UP'") //Turn Group On
}
ELSE
{
AddtoViziaRFQue ("'>GR',cGroup,'OF,UP'") //Turn Group Off
}
}
ELSE IF (nType < 400)
{
cType = 'Scene'
Send_String 0,"cType"
cScene = ITOA(nButtonIndex)
AddtoViziaRFQue ("'>?S',cScene") //Gets the status of the Light Scene
IF (cStatus = 'OF')
{
AddtoViziaRFQue ("'>S',cScene,'ON,UP'") //Turn Scene On
}
ELSE
AddtoViziaRFQue ("'>S',cScene,'OF,UP'") //Turn Scene Off
}
}
}
DATA_EVENT [dvViziaRF]
{
ONLINE:
{
SEND_STRING dvViziaRF , 'SET BAUD 9600,N,8,1'
}
STRING:
{
STACK_VAR CHAR cTemp[17] // Max 17 characters in the received data from Vizia RS232 module
cTemp = (DATA.TEXT)
IF (length_string(cTemp) == 5) //If data is 5 characters it is an error or infomation
{
cTypeData = 'Info'
cMessage = MID_STRING(cTemp, 2, 4)
}
ELSE IF (length_string(cTemp) == 9) //If data is 9 characters it is a level or status
{
cTypeData = 'Status'
cMessage = MID_STRING(cTemp, 6, 4)
IF (find_string(cTemp, 'N', 1) == 1) //If this is a switch or dimmer
{
cNode = "'1', MID_STRING(cTemp, 4, 2)" //Strip the >N0 and add 1 to the beginning for TP Node Button Number
nNode = ATOI(cNode)
}
ELSE IF (find_string(cTemp, 'G', 1) == 1)
{
cNode = "'2', MID_STRING(cTemp, 4, 2)" //Strip the >G0 and add 2 to the beginning for TP Group Button Number
nNode = ATOI(cNode)
}
ELSE IF (find_string(cTemp, 'S', 1) == 1)
{
cNode = "'3', MID_STRING(cTemp, 4, 2)" //Strip the >S0 and add 1 to the beginning for TP Scene Button Number
nNode = ATOI(cNode)
}
}
SWITCH(cMessage)
{
CASE 'L255':
{
cStatus = 'ON'
nLiteStatus[nNode] = 1
}
CASE 'L000':
{
cStatus = 'OF'
nLiteStatus[nNode] = 0
}
// RF Transmission Messages
CASE 'X000': //No RF Transmission Error
{
ON[nReady]
}
CASE 'X002': //RF Transmission Error
{
ON[nReady]
}
// Errors sent from the Vizia RS-232 Module
CASE 'E001': //wrong start of the string symbol
CASE 'E002': //Input buffer overflow.
CASE 'E003': //Can not start RF transmission. All buffers are taken.
CASE 'E004': //Can not start RF transmission because previous one has not finished.
CASE 'E005': //Unrecognized command
CASE 'E006': //Attempt to send the new buffer over RS232 before previous one had been processed.
CASE 'E007': //The send Message does not have data fields specified.
CASE 'E008': //Can not stop SUC mode. Node is SUC.
CASE 'E009': //EERPOM is busy, can’t store group information
CASE 'E010': //No devices with specified properties have been found
{
ON[nReady]
}
}
}
}
(***********************************************************)
(* THE ACTUAL PROGRAM GOES BELOW *)
(***********************************************************)
DEFINE_PROGRAM
SendViziaRFQue()
for (x =1;x<41;x++)
{
[dvTP,nTPbuttons[x]] = nLiteStatus[nTPbuttons[x]]
}
(***********************************************************)
(* END OF PROGRAM *)
(* DO NOT PUT ANY CODE BELOW THIS COMMENT *)
(***********************************************************)
Don't let the command que back up to much. It looks real goofy then the communications are ready and the system spits out 2 minutes of commands because the que was backed up. O yeah, If you don't define the size/length of the CHAR variables you get this warning.
C10571: Converting type [string] to [CHAR] - should I be worried about these, is there a way to correct the problem? I saw a tech note on how to disable the warnings but do they affect anything?
Don't let the command que back up to much. It looks real goofy then the communications are ready and the system spits out 2 minutes of commands because the que was backed up. O yeah, If you don't define the size/length of the CHAR variables you get this warning.
Thanks that fixed the warnings, what kind of advice can you offer on how to keep the queue from backing up? I do know that I need to see one of the Xyyy or Eyyy events returned from the lighting interface before I can send the next command that is why I put the nReady change in the data_event after those strings.
Add to the front of the que and limit the size of the que. This would push old commands out of the que leaving the most recent commands to be executed. Like FILO First in last out. Not FIFO.
Yes! but the problem exists, if the lighting system is not ready for a command and someone is pressing the buttons repeatedly the que becomes backlogged with commands Then when it is finally ready, the que parses sending the lighting system tons of old commands before it gets to the current command. There needs to be a limit of commands stored in the que and the most recent command should be processed first. I figured just stacking them in FILO and limiting the size of the que would solve this delimma,
I personally would not que commands for a lighting system. Just send the last command when it's ready.
Normally most equipment responds fast enough so that you don't fill the queue that much unless you really push alot and fast, with the exception of hold and repeats for raise/lower lighting levels. It's more often used for timing. Send command, receive response and check queue for more commands and if the queue holds any send the next command type of thing. Keeps you from stepping on your previous command or sending when the device is still processing the previous command. Unless the Leviton device is a real dog I would stick with a FIFO type buffer (queue) since your 1st push may be to turn on the light and the next may be to increase its intensity doing that in reverse order will likely accomplish nothing.
Everything is going ok with this. The one thing I am having an issue with is updating the text on some of the TP buttons.
Example
send_string dvTP, "'^TXT-301,0,',cSunset"
cSunset is a string and also button 301 is programmed as a general button and right now address code 301, I have also tried it with 301 as a channel code on the button. I see it in the NS2 diagnostics window as being sent with the appropriate information but it is not updating. Could someone inform me as to what stupid thing I am doing wrong. Thanks
Everything is going ok with this. The one thing I am having an issue with is updating the text on some of the TP buttons.
Example
send_string dvTP, "'^TXT-301,0,',cSunset"
cSunset is a string and also button 301 is programmed as a general button and right now address code 301, I have also tried it with 301 as a channel code on the button. I see it in the NS2 diagnostics window as being sent with the appropriate information but it is not updating. Could someone inform me as to what stupid thing I am doing wrong. Thanks
You need to use SEND_COMMAND not SEND_STRING to send variable text to button.
Ok, I actually installed the equipment today. I am having an issue with the send_strings and what I am receiving. I verified that I can communicate to the ViziaRF module with hyperterm and was able to send the commands and receive the feedback with no problem. When send the commands from the processor it looks like it is HEX when I need it to be ASCI and the same thing in the feedback repsonses, is this normal? Does the processor take everything back in as HEX? If so then I need to fix my STRING processing in my programming. So here is what I am talking about. Also I tried to receiving the commands from the process into hyperterm but just got garbage due to the HEX (I beleive)
Diagnostics
Line 85 (10:20:03):: Added Leviton Command: >?N4
Line 86 (10:20:03):: Added Leviton Command: >N4ON
Line 87 (10:20:03):: Added Leviton Command: >?N4
Line 88 (10:20:03):: Sent Leviton Command: >?N4$0D
Line 89 (10:20:03):: Sent Leviton Command: >N4ON$0D
Line 90 (10:20:03):: Sent Leviton Command: >?N4$0D
Line 91 (10:20:03):: 0
Line 92 (10:20:22):: Exiting UDP SNMP Read thread - closing this socket for local port 3
Line 93 (10:20:22):: CIpEvent::OffLine 0:3:1
Line 94 (10:20:47):: 0
Line 95 (10:20:47):: 120
Line 96 (10:20:51):: 0
Line 97 (10:20:51):: 128
Notification
Line 14 (10:20:03):: Input Status:Pushed [10001:1:1] - Channel 104
Line 15 (10:20:03):: String To [5001:1:1]-[>?N4$0D]
Line 16 (10:20:03):: String To [5001:1:1]-[>N4ON$0D]
Line 17 (10:20:03):: String To [5001:1:1]-[>?N4$0D]
Line 18 (10:20:03):: String From [5001:1:1]-[$00$80x$00x$80$00$80$80$80$80x$00$80x]
Line 19 (10:20:03):: Input Status:Released [10001:1:1] - Channel 104
Line 20 (10:20:47):: String From [5001:1:1]-[$00$80$80$80x$80$00$80x$80$80$F8$80x$80$00$F8$80x$F8$80$00x$00$80$00$80$00$80$00x$00$80$80$80$80x$80$00x$00$80x$80$80$80$80$00x$00$80$00$80$F8$80$80$00x$00$80$00$80x$80]
Line 21 (10:20:47):: String From [5001:1:1]-[x$00$80x]
Line 22 (10:20:51):: String From [5001:1:1]-[$00$80$80$80x$80$00$80x$80$80$F8$80x$80$00$F8$80x$F8$80$00x$00$80$00$80$00$80$00x$00$80$80$80$80x$80$00x$00$80x$80$80$80$80$00x$00$80$00$80$F8$80$80$00x$00$80$00$80$80$80]
Line 23 (10:20:51):: String From [5001:1:1]-[$80x$00$80x]
Here is my code
PROGRAM_NAME='ClientXXX'
(***********************************************************)
(***********************************************************)
(* FILE_LAST_MODIFIED_ON: 11/26/2008 AT: 14:01:38 *)
(***********************************************************)
(* System Type : NetLinx *)
(***********************************************************)
(* REV HISTORY: *)
(***********************************************************)
(*
$History: $
*)
(***********************************************************)
(* DEVICE NUMBER DEFINITIONS GO BELOW *)
(***********************************************************)
DEFINE_DEVICE
dvTP = 10001:1:0
dvViziaRF = 5001:1:0
(* Buad = 9600
data bits = 8
stop bit = 1
parity = no parity
Handshaking = off *)
vdvViziaRF = 33002:1:0
vdvSchEvents = 33003:1:0
dvTmTimeSync = 0:3:0
(***********************************************************)
(* CONSTANT DEFINITIONS GO BELOW *)
(***********************************************************)
DEFINE_CONSTANT
INTEGER nTPLiteButtons[] =
{
//Lighting Nodes - Individual Switches/Dimmers
101, //Light Node Button 1 - VRCPG Controller
102, //Light Node Button 2 - RS-232 Module
103, //Light Node Button 3 - Driveway
104, //Light Node Button 4 - Garage
105, //Light Node Button 5 - Brick Left
106, //Light Node Button 6 - Brick Right
107, //Light Node Button 7 - Front Island
108, //Light Node Button 8 - Front Accent Right
109, //Light Node Button 9 - Front Accent Left
110, //Light Node Button 10 - Rear Accent
111, //Light Node Button 11 - Pool Accent
112, //Light Node Button 12 - Cabana External
113, //Light Node Button 13 - Cabana Sofit
114 //Light Node Button 14 - Doghouse
}
INTEGER nTPGroupButtons[] =
{
//Lighting Groups - A set of switches/Dimmers to behave as one node
201, //Light Group Button 1
202, //Light Group Button 2
203, //Light Group Button 3
204, //Light Group Button 4
205, //Light Group Button 5
206, //Light Group Button 6
207, //Light Group Button 7
208, //Light Group Button 8
209, //Light Group Button 9
210 //Light Group Button 10
}
(* Timeserver protocols *)
nProtoNone = 0
nProtoDaytime = 1
nProtoTime = 2
nProtoSNTP = 3
nProtoSNTPBCast = 4
(***********************************************************)
(* VARIABLE DEFINITIONS GO BELOW *)
(***********************************************************)
DEFINE_VARIABLE
VOLATILE CHAR cLastcCmd[20] //Stores last sent command
VOLATILE CHAR cType[5] //Stores Selected Node Type
VOLATILE CHAR cTypeData[6] //Stores the type of device on feedback
VOLATILE CHAR cNode[3] //Stores Selected Light Node
VOLATILE CHAR cGroup[3] //Stores Selected Light Group
VOLATILE CHAR cScene[3] //Stores Selected Light Scene
VOLATILE CHAR cStatus[3] //Stores Status of Selected Light Zone
VOLATILE CHAR cMessage[255] //Stores Light Node/Group/Scene Level error information
VOLATILE CHAR cCable[3]
Char cViziaRFQue[60] //ViziaRF Que
VOLATILE CHAR cSunrise[30]
VOLATILE CHAR cSunset[30]
VOLATILE CHAR cLocation[100]
VOLATILE CHAR cPrevSunrise[30]
VOLATILE CHAR cPrevSunset[30]
VOLATILE CHAR cPrevLocation[100]
VOLATILE CHAR cReady //Flag for waiting for response from Lights
INTEGER nLiteStatus[21] //Stores Light Status for feedback on TP
INTEGER nGroupStatus[11] //Stores Group Status for feedback
INTEGER nNode //Stores Selected Light Node for Array position
INTEGER nStatus
INTEGER nGroup //Stores Selected Light Group for Array position
INTEGER nScene //Stores Selected Light Scene for Array position
INTEGER nType //Stores Selected Light Type for Array Position
INTEGER nTPOnline
x //Count in For Loop for lite feedback
y //Count in For Loop for Group feedback
(* Timezone *)
CHAR dTmTzName[100]
CHAR dTmTzDesc[10]
DOUBLE dTmTzGmtOffset
CHAR strTmTzDstRules[1000]
(* Location *)
CHAR strTmLocName[100]
DOUBLE dTmLocLong
DOUBLE dTmLocLat
(* Timeserver *)
INTEGER nTmTsProtocol
INTEGER nTmTsCheckTime
CHAR strTmTsServer[100]
(***********************************************************)
(* Define Device Combining Here *)
(***********************************************************)
DEFINE_COMBINE
(***********************************************************)
(* Function/Calls Code Goes Here *)
(***********************************************************)
Define_Function SendViziaRFQue ()
{
Local_Var Char cCmd[20]
If(![dvViziaRF,cReady] && Length_String(cViziaRFQue))
{
cCmd = Remove_String(cViziaRFQue,"13",1)
cLastcCmd = cCmd
Send_String dvViziaRF,"cCmd"
Send_String 0,"'Sent Leviton Command: ',cCmd"
OFF[cReady]
}
}
Define_Function AddtoViziaRFQue (Char cCmd[20])
{
cViziaRFQue = "cViziaRFQue,cCmd,13"
Send_String 0,"'Added Leviton Command: ',cCmd"
}
(***********************************************************)
(* STARTUP CODE GOES BELOW *)
(***********************************************************)
DEFINE_START
dTmTzName = 'Eastern'
dTmTzDesc = 'E%sT'
dTmTzGmtOffset = -5.0
strTmTzDstRules = 'US'
strTmLocName = 'Rehoboth, MA 02769'
dTmLocLong = -71.25
dTmLocLat = 41.84
nTmTsProtocol = nProtoSNTP
nTmTsCheckTime = 0
strTmTsServer = ''
cReady = '0'
(***********************************************************)
(* THE EVENTS GO BELOW *)
(***********************************************************)
DEFINE_EVENT
BUTTON_EVENT [dvTP, nTPLiteButtons]
{
PUSH:
{
STACK_VAR INTEGER nLiteButtonsIndex
nLiteButtonsIndex = GET_LAST(nTPLiteButtons)
cNode = ITOA(nLiteButtonsIndex)
AddtoViziaRFQue ("'>?N',cNode") //gets the status of the Light Zone
IF (nLiteStatus[nLiteButtonsIndex] = 0)
{
AddtoViziaRFQue ("'>N',cNode,'ON'")
AddtoViziaRFQue ("'>?N',cNode")
}
ELSE
{
AddtoViziaRFQue ("'>N',cNode,'OFF'") //Turn Light Zone Off
AddtoViziaRFQue ("'>?N',cNode")
}
}
}
BUTTON_EVENT [dvTP, nTPGroupButtons]
{
PUSH:
{
STACK_VAR INTEGER nGrouButtonsIndex
nGrouButtonsIndex = GET_LAST(nTPGroupButtons)
cGroup = ITOA(nGrouButtonsIndex)
AddtoViziaRFQue ("'>?GR',cGroup") //Gets the status of the Light Group
IF (nGroupStatus[nGrouButtonsIndex] = 0)
{
AddtoViziaRFQue ("'>GR',cGroup,'ON'") //Turn Group On
AddtoViziaRFQue ("'>?G',cGroup")
}
ELSE
{
AddtoViziaRFQue ("'>GR',cGroup,'OFF'") //Turn Group Off
AddtoViziaRFQue ("'>?G',cGroup")
}
}
}
BUTTON_EVENT[vdvSchEvents,1] //Group 1 On/Off
{
PUSH:
{
AddtoViziaRFQue ('>G1ON')
}
RELEASE:
{
AddtoViziaRFQue ('>GR1OFF')
}
}
DATA_EVENT [dvViziaRF]
{
ONLINE:
{
SEND_STRING dvViziaRF , 'SET BAUD 9600,N,8,1,OFF'
AddtoViziaRFQue ('>?N')
AddtoViziaRFQue ('>N7,8,9GS1') //Landscape Light Group
//AddtoViziaRFQue ('>N8,9,10,11,7GS2')
}
STRING:
{
STACK_VAR CHAR cTemp[17] // Max 17 characters in the received data from Vizia RS232 module
cTemp = itoa(DATA.TEXT)
send_string 0, "cTemp"
SELECT
{
ACTIVE (FIND_STRING(cTemp,'<N',1)): //Looks to see if it is a Node Level Status
{
REMOVE_STRING (cTemp,'<',1) //Makes the message NxxxLyyy
SEND_STRING 0,"'Node',cTemp"
cNode = MID_STRING(cTemp,2,3)
nNode = ATOI(cNode)
cStatus = MID_STRING(cTemp,6,3)
nStatus = ATOI(cStatus)
IF (cStatus == '000')
{
nLiteStatus[nNode] = 0
}
ELSE IF (cStatus == '255')
{
nLiteStatus[nNode] = 1
}
}
ACTIVE (FIND_STRING(cTemp, '<G',1)): //Looks to see if it is a Group Level Status
{
REMOVE_STRING (cTemp,'<',1) //cTemp is now GxxxLyyy
SEND_STRING 0,"'Group',cTemp"
}
ACTIVE (FIND_STRING(cTemp, '<X',1)): //Looks to see if it is a RF Transmission Status
{
REMOVE_STRING (cTemp,'<',1) //cTemp is now Xxxx
SEND_STRING 0, "'RF Trans', cTemp"
cReady = '0' //ViziaRF is ready to receive a command
IF (cTemp == 'X002')
{
AddtoViziaRFQue(cLastcCmd)
}
}
ACTIVE (FIND_STRING(cTemp, '<E',1)): //Looks to see if it is an Error Message
{
REMOVE_STRING (cTemp,'<',1) //cTemp is now Exxx
SEND_STRING 0, "'Error', cTemp"
ON[cReady]
}
ACTIVE (FIND_STRING(cTemp, '<F',1)): //Found new node message
{
REMOVE_STRING (cTemp,'<',1) //cTemp is now Fxxx
SEND_STRING 0, "'Found Node', cTemp"
}
ACTIVE (FIND_STRING(cTemp, '$00',1)):
{
ON[cReady]
}
}
}
}
DATA_EVENT[vdvSchEvents]
{
STRING:
{
STACK_VAR
CHAR strUpper[30]
CHAR strTemp[30]
CHAR strTrash[30]
strUpper = UPPER_STRING(DATA.TEXT)
strTemp = DATA.TEXT
strTrash = REMOVE_STRING(strTemp,'-',1)
SELECT
{
(* SUNRISE *)
ACTIVE (FIND_STRING(strUpper,'SUNRISE-',1)):
{
SEND_STRING 0,"'Sunrise Time=',strTemp"
cSunrise = strTemp
}
(* SUNSET *)
ACTIVE (FIND_STRING(strUpper,'SUNSET-',1)):
{
SEND_STRING 0,"'Sunset Time=',strTemp"
cSunset = strTemp
}
(* TIME ZONE NAME *)
ACTIVE (FIND_STRING(strUpper,'TIMEZONE-',1)):
SEND_STRING 0,"'Timezone=',strTemp"
(* TIME DESCRPTION *)
ACTIVE (FIND_STRING(strUpper,'TIMEDESC-',1)):
SEND_STRING 0,"'Time Description=',strTemp"
(* LOCATION *)
ACTIVE (FIND_STRING(strUpper,'LOCATION-',1)):
{
SEND_STRING 0,"'Location=',strTemp"
cLocation = strTemp
}
}
}
ONLINE:
{
(* Debug *)
//ON[vdvSchEvents,250]
(* Setup events *)
(* Group 1 On - start at 7:00 PM and end at 10:00 PM Daily *)
SEND_COMMAND vdvSchEvents,"'SET EVENT-1,Group 1,Daily,18:00,22:00'"
// (* Group 2 On - start at 7:00 PM and end at 10:30 PM Daily *)
// SEND_COMMAND vdvSchEvents,"'SET EVENT-2,Group 2,Daily,19:30,22:30'"
}
}
DEFINE_MODULE 'i!-ScheduleEngineMod' mdlSch(vdvSchEvents,
dvTmTimeSync,
(* Timezone *)
dTmTzName,
dTmTzDesc,
dTmTzGmtOffset,
strTmTzDstRules,
(* Location *)
strTmLocName,
dTmLocLong,
dTmLocLat,
(* Timeserver *)
nTmTsProtocol,
nTmTsCheckTime,
strTmTsServer)
(***********************************************************)
(* THE ACTUAL PROGRAM GOES BELOW *)
(***********************************************************)
DEFINE_PROGRAM
SendViziaRFQue()
for (x =3;x<13;x++)
{
[dvTP,nTPLiteButtons[x]] = nLiteStatus[x]
}
For (y =1;y<11;y++)
{
[dvTP,nTPGroupButtons[y]] = nGroupStatus[y]
}
(***********************************************************)
(* END OF PROGRAM *)
(* DO NOT PUT ANY CODE BELOW THIS COMMENT *)
(***********************************************************)
Thank you kbeatty I got. I remembered someone saying that SEND_COMMAND was for virtual devices and SEND_STRING was for real devices. So I will change that and try again.
Comments
and the case statements can be stacked...
Also I would use channels on the Virtual or Actual device as much as possible. This give access to what is going on with this control system to other AMC control systems. If your just changing a variable from 0 to 1, that information is only accessible by the local controller.
wouldn't it be great if you could do some kind of array for a stacked case...
Also, be careful using a FOR loop in DEFINE_PROGRAM, it's a huge process hog. If you wind up seeing a performance hit, you can easily let the load off by surrounding your FOR loop with a WAIT 2 . . . your eye is not going to notice a 2/10 of a second delay in updating feedback.
You then might consider creating a queue so you only send commands after a response from the previous command is received. Put in a time out period via a wait in case a valid response isn't received in a resonable amount of time so you can send the next string in queue. The way the code is now you could possible keep pushing buttons and sending strings before getting any replies back and being nReady. Some devices don't like that. You could also block further button pushes if nReady isn't ready but that might piss off the user so you're better off using a queue.
Not too sure if there is that much difference in processing. Everytime mainline is processed 40 loops of the FOR loop is processed with 1 line of feedback per loop. OR 40 lines of Feedback in each loop of mainline. Seems like a wash to me... Just a lot of less typing with the FOR loop. Also virtual devices start at 33001.
>N8OF,UP - Turn light node 8 Off, and requests an update.
<E000 - Acknowledges the command
<X000 - RF Transmission was sent successfully (X002 means unsuccessfully)
<N008L000 - Returns the status of the light node
If I do not put the ",UP" on the command I would only get this:
>N8OF,UP - Turn light node 8 Off, and requests an update.
<E000 - Acknowledges the command
<X000 - RF Transmission was sent successfully
I also found out that the "X000 or X002" means that I can send another command so that is where I should set the nReady state and not on the other feedback messages.
I have not done anything with the Error codes yet not sure if I will do anything with them or not
I have them defined the virtual devices but have not used them yet I may get rid of them and I corrected the addressing for now.
Not sure if you are being sarcastic or not but yest that would be great, is this allowed?
Not a 100% what this is actually performing. nReady is just a flag that I am using to make sure that the device is ready to receive another command.
I would love to use a buffer to send the commands I just need to figure out how.
Also if there is a change of status to any light that is done by the light switch itself the level info would be sent to the Netlinx so would I really need the feedback in the DEFINE_PROGRAM section?
Hey - don't get me wrong, it's helpful and yes - I do FOR loops in DEFINE_PROGRAM. I've a couple of programs where the FOR loop crippled the system . . . breaking it up with a WAIT or removing some of it and doing direct feedback helped. And I should mention, these were larger systems (18 touch panels in one job, with lighting feedback.)
I'm not much of a benchmark guy, but if anyone has any numbers that'd be great. I heard numbers before in Programmer 3 - but to be honest, forgot them.
C10571: Converting type [string] to [CHAR] - should I be worried about these, is there a way to correct the problem? I saw a tech note on how to disable the warnings but do they affect anything?
Thanks that fixed the warnings, what kind of advice can you offer on how to keep the queue from backing up? I do know that I need to see one of the Xyyy or Eyyy events returned from the lighting interface before I can send the next command that is why I put the nReady change in the data_event after those strings.
more like this...
Actually the function as coded above acts as a stack (Last In First Out) vs a Queue (First In First Out).
I personally would not que commands for a lighting system. Just send the last command when it's ready.
Example
cSunset is a string and also button 301 is programmed as a general button and right now address code 301, I have also tried it with 301 as a channel code on the button. I see it in the NS2 diagnostics window as being sent with the appropriate information but it is not updating. Could someone inform me as to what stupid thing I am doing wrong. Thanks
So then I would need to create a virtual device for the TP, seeing the SEND_COMMAND is for virtual device correct?
Diagnostics
Line 85 (10:20:03):: Added Leviton Command: >?N4
Line 86 (10:20:03):: Added Leviton Command: >N4ON
Line 87 (10:20:03):: Added Leviton Command: >?N4
Line 88 (10:20:03):: Sent Leviton Command: >?N4$0D
Line 89 (10:20:03):: Sent Leviton Command: >N4ON$0D
Line 90 (10:20:03):: Sent Leviton Command: >?N4$0D
Line 91 (10:20:03):: 0
Line 92 (10:20:22):: Exiting UDP SNMP Read thread - closing this socket for local port 3
Line 93 (10:20:22):: CIpEvent::OffLine 0:3:1
Line 94 (10:20:47):: 0
Line 95 (10:20:47):: 120
Line 96 (10:20:51):: 0
Line 97 (10:20:51):: 128
Notification
Line 14 (10:20:03):: Input Status:Pushed [10001:1:1] - Channel 104
Line 15 (10:20:03):: String To [5001:1:1]-[>?N4$0D]
Line 16 (10:20:03):: String To [5001:1:1]-[>N4ON$0D]
Line 17 (10:20:03):: String To [5001:1:1]-[>?N4$0D]
Line 18 (10:20:03):: String From [5001:1:1]-[$00$80x$00x$80$00$80$80$80$80x$00$80x]
Line 19 (10:20:03):: Input Status:Released [10001:1:1] - Channel 104
Line 20 (10:20:47):: String From [5001:1:1]-[$00$80$80$80x$80$00$80x$80$80$F8$80x$80$00$F8$80x$F8$80$00x$00$80$00$80$00$80$00x$00$80$80$80$80x$80$00x$00$80x$80$80$80$80$00x$00$80$00$80$F8$80$80$00x$00$80$00$80x$80]
Line 21 (10:20:47):: String From [5001:1:1]-[x$00$80x]
Line 22 (10:20:51):: String From [5001:1:1]-[$00$80$80$80x$80$00$80x$80$80$F8$80x$80$00$F8$80x$F8$80$00x$00$80$00$80$00$80$00x$00$80$80$80$80x$80$00x$00$80x$80$80$80$80$00x$00$80$00$80$F8$80$80$00x$00$80$00$80$80$80]
Line 23 (10:20:51):: String From [5001:1:1]-[$80x$00$80x]
Here is my code
It should be:
Thank you for the clarification on that.
So I should change these to SEND_COMMAND?