NetLinx Coding best practice...
hodeyp
Posts: 104
Hi,
I am looking at my 'macro' code where I am executing multiple events. e.g. Switching to DVD would...
Turn on DVD Player
Turn on Plasma
Switch AV processor to DVD
Switch Video processor to DVD
Turn down lights
I have lots of these routines as I am sure everybody else does too. Question I have is how best to code these.
I am using modules for each where each command is built into a button event. If I am looking to combine several actions should I assign another button event and attach a series of DO_PUSH commands?
Not sure if it really matters but would be interested in what is considered best practice as I have on more than one occassion written stuff that looks fine and technically is fine but due to netlinx oddities has thrown lots of runtime exceptions...
I am looking at my 'macro' code where I am executing multiple events. e.g. Switching to DVD would...
Turn on DVD Player
Turn on Plasma
Switch AV processor to DVD
Switch Video processor to DVD
Turn down lights
I have lots of these routines as I am sure everybody else does too. Question I have is how best to code these.
I am using modules for each where each command is built into a button event. If I am looking to combine several actions should I assign another button event and attach a series of DO_PUSH commands?
Not sure if it really matters but would be interested in what is considered best practice as I have on more than one occassion written stuff that looks fine and technically is fine but due to netlinx oddities has thrown lots of runtime exceptions...
0
Comments
Stacking a bunch of Do_Push statements is quick and dirty way to get a marco to run. Unfortunately you are using the mindset of the typical 'Smart' remote that has no timing capability.
A better approach would be to develop a Timeline that will better trigger the individual commands in the proper sequence and time.
For example, if you fire the plasma power on command the plasma may not immediately accept an input command. The goal is choreograph the control events to activate in an intelligent manner. You should also consider the results if the user selects a different marco (or any other button) while the first macro is running. Also, why continue to send a power on command if the device is already on?
It would be very easy to spend a couple hour exploring this subject in an advanced training class.
e.g. - I see no reason why a user should have to switch the plasma on at all, as it is entirely dependant on what source they will be using. As such this should just happen in the background.
However, the module is expecting a button press from the touchpanel, I don't really want to fill the touchpanel with buttons that a user never need press.
I suppose the question could be written, what is the best way to switch a device on without user interaction?
Instead of building your modules around a touch panel BUTTON_EVENT, you could just as easily use a CHANNEL_EVENT on a virtual device. That way your main code can PULSE a channel on the virtual device to activate the code for the physical device.
Also, if I am understanding your question correctly, just because you use a DO_PUSH in your program you really don't need a physical button on the touch panel representing the DO_PUSH channel. There is no reason to put unnecessary buttons on a touch panel.
As Dave said there is no best way. It is just a matter of style and functionality. My preference to use various CALLS or FUNCTIONS that can be activated by the BUTTON_EVENT. Like Dave, the WAIT_UNTIL statement is one of my favorite ways to manage conditional timing.
Search for 'NetLinx Programming Conventions' on the AMX site and check out the modules section.
Also download any module and look at the accompanying API specification that comes with it.
AMX also has a macro manager module but I find it far too bloated for standard use. It is definitely worth looking at though to get ideas.
I wanted to create a standard way for my company to program and found that AMX have already written the documents. Start there and extrend their API.
Also check out the code created by Design Express for ideas.
Reading other peoples code is a great way to get ideas.
One thing to consider is that when doing a series of DO_PUSH (or sending a series of any other type of events for that matter), they will all be handled sequentially (one after the other). Now if the resulting code in your module does "stack" other events (like pulsing IR) and/or send RS232 commands, you have now a lot of events in the queue. If some of the code now expects feedback from a VSS2 or from RS232 and you have time outs defined, then this code has to take into account the queue depth and the delay in handling it. I think we found out in another thread the delay will apply to all events and waits but not to timeline events.
This could explain why a module works perfectly in stand alone mode, but fails or otherwise behaves strangely when used in concert with others within macros. There's just too much stuff happening and the master runs late.
In residential situations I believe there is a value in sequencing things properly. For example the video projector might spend its time "detecting" various signals while the scaler is booting, so you want to turn it on only once the scaler has booted. Ultimately you're bound to want more control than just throwing out the complete command set vaguely in order and hope for the best.
A solution are timelines as mentioned, or the AMX "macro" system. They also have something in DXP home theater you can have a look at.
I do have a complete ('bloated') sequencing system with automatic time outs and delays that can SEND_COMMANDs or IR or whatever. The sequence is built dynamically when needed, so it only includes required steps. Now that I have it is much simpler for me to use it than to bother with a timeline, but it has a cost in code size. I can also use it to program RS232 devices.
It is my opinion that such a feature is such a basic building block of an automation system that I don't understand why it is not part of the NetLinx language.
HTH
Fred
"This keyword is useful only in limited situations, and its use is strongly discouraged."
If this is in reference to DO_PUSH, it was given a new life (and almost a blessing?) in Netlinx. If you look in the Netlinx programming manuals, (or online help in NLStudio) you'll see that it doesn't have the disclaimer that the Axcess manual used to have.
Haven't run into a situation where I've needed it, but it supposedly isn't the "bad thing" that it used to be in Axcess.
- Chip
As Chip said...no prolbems in NetLinx.
The problem in Access is that while a DO_PUSH was in progress the implied DO_RELEASE needed to occur before accepting the next button push. It was difficult to manage DO_PUSH in Access without a thorough understanding of how MAIN LINE operates. Thus limited value unless you really knew what you were doing.
thx again!
The other time you would use them, and I think this is the more important one, is when you have a fair amount of stuff going on in a button event, but not enough to warrant creating a seperate function or CALL for it. Or perhaps you have a virtual panel with it's own button events. Do you really want to duplicate that button event code if you need it fired in another place? Just use a DO_PUSH instead. There is no need to retype the same code in three spots. Or, if those same three lines of code are buried inside a module, and are not accessible, but the button devchan itself is - then a DO_PUSH is the logical way to fire those three lines without needing to modify the module. I've used this with a CCTV controller. The panel to control the controller itself, of course, has a way to select cameras, and make sure whatever needs to be updated gets updated. But I wanted to switch to a specific camera under certain conditions, and still make sure all those updates and things happened the way they were supposed to (this controller has no real feedback, I had to track myself what camera was being displayed). A judicious DO_PUSH on the control panel devchan did the job neatly and nicely, ans as long as the controller module did it's job properly, I didn't have to worry about it elsewhere.
It's all about avoiding code redundancy, in my book. Functions and CALL's (for those of us who haven't sworn off them) are fine in many applications, but sometimes a judicious DO_PUSH does the job even better. The real thing to avoid is a chain of DO_PUSH's that might wind up calling an endless loop, or call another DO_PUSH. They are like soy sauce - used them sparingly and carefully, and they can enhance your project. Too much, or used wrongly, and it's just nasty.
Poetry - sheer poetry...
- Chip
It's kinda hard to answer this question without some design scope or code.
but one idea might be a function that has the things you're talking about in the call.
For example:
define_Function my_big_function( integer Room_ID, integer Command_ID, char etc...)
{
}
So, in a way you're creating the same functionality as an array of functions but essentially storing the data table in the function itself.
Turn on tv array device 1-8
Set autopatch zone to source
Set zone flag for tracking zone status
Turn on ir device selected.
I'm on my phone now, otherwise I would copy and paste some code I'm working on. I am using a home brewed version of some autopatch switcher code where I can select multiple rooms first, then select the device needed, and then have those zones all change. However, I'm at a standstill with determining if I should continue with my individual functions, or look at incorporating them all into the button events for the switcher. The problem with that becomes the handheld remotes that use the existing functions to do macros.
All of the AVR power on waits (if needed) are handled by my AVR modules. All of the individual source power stats are handled in a separate function that is called elsewhere in the program.
I did not include the structure declarations, variable declarations or external functions, but this is just to get an idea of how I handle this.
It works pretty well in that I only have to edit the function for rooms with surround receivers or local sources. Otherwise I let everything fall through to the default case and it handles everything for me.
A define_call most certainly has its place. I've seen enough Other People's Code to say "why is he using a function here? It doesn't return a value!" I use functions for stuff like scaling a number, calculating a checksum, that sort of thing. But almost every one of my projects includes a call like "define_call 'shutdown' (integer room)".
.
In my experience, a function cannot return an array; it has to be a scalar. But maybe I've misunderstood the question.
Actually you can return a CHAR array, but not any other kind
.
Is there a performance hit for using functions instead of calls?
I prefer to use functions because I find the autocomplete and highlighting in NS3 to be much easier to deal with when using functions instead of calls. I also really like the popup that spells out which parameters the function is expecting when typing code and you do not get the same useful information when calling a call.
I don't think there is anything significant. Just use whatever you are most comfortable with, I doubt in the long run it will matter enough to be concerned about.