Home AMX User Forum NetLinx Studio

notification design question

Hi all

As I told before, I am working on a big house (10 NI 3100, 12 TP, 150+- devices, 2 LUTRONS etc etc....)

I am making a design for my program now and since this is my first home in AMX, I am trying to solve all the things that might influence my design.

My question is about notifications.

I need every screen on every TP to be full updated on the devices/house status.
from my previeus experince in other systems, I made the page to listen to events to get updated, and to ask for the data when page load.

My problem is when page load, if some serial devices will take time and make the UI look slow...

the solution is to hold a data mirror of the important information device that will get update all the time even and when the page loaded to fech the data from the data mirror.
This is not simple to do for 150 devices and need an event handler + listener pattern to be implemented.


My question is how do you guys save your pages to be update with the serial devices?

for example an audio distribution system that need to show on a room map graphicaly?
or a simple TV screen?

what with SET TOP BOX that works with IR? how do you save the channel?

thanks for any idea


Ady.

Comments

  • GSLogicGSLogic Posts: 562
    Ady

    I think of it like this:
    All section get a port (Lighting 10001:2:0, Security 10001:3:0, Music 10001:4:0, etc.)
    All device (Lighting, Security, Music) get a STRUCTURE/ARRAY that hold their own sections info.
    When a panel enters that section (Lighting, Security, Music), I update only that panel with the info needed.

    The hard part is tracking the panels in the system and knowing where they are so you're not updating panels for no reason. The only time the Security section should send data to a panel is when there is a panel viewing the Security section and so forth. I also don't use DEFINE_PROGRAM for any feedback. I use this method for large systems that need to conserve processing power.

    Hope this helps!
  • adysadys Posts: 395
    Thanks, is helps. Sort that what I thought of doing. I also got some ideas from looking at design express code ( how much the Visual architect code is better BTW? )

    its is one thing to implement a data mirror and ot make a smart update. a simple event handler/listener mechanizem can help in this case.

    I need to hold the data only in the controller that hold the device, so I must listen to every page chagne on every TP, and according to this to send the appropirate data to the TP?


    I didn't get the DEFINE_PROGRAM part...
  • yuriyuri Posts: 861
    you could do something like this:

    make a dev array with all the touchpanels in your system.
    Then, somewhere in your code, you could do this:
    BUTTON_EVENT[allTPs, securityButton]
    {
      push:
      {
        local_var integer i
        i = get_last(allTPs)
    
        //have a function update security stuff
        updateSecurity(i)
    
        //send tp to page
        SEND_COMMAND allTPs[i], 'PAGE-Security'
      }
    }
    
    

    where allTPs is your dev array, and securityButton is your channel code :)

    hope this helps abit, i think it's the best way to update information
  • GSLogicGSLogic Posts: 562
    adys wrote:
    I didn't get the DEFINE_PROGRAM part...

    Older style programming used the DEFINE_PROGRAM for button feedback and such. In very large systems this can slow things down, so I only send feedback to panels needing information. If it's a smaller system 1-4 panels, I'm not sure I'd even worry about it, but it is a good habit to get into.
  • Limiting feedback

    It's quite easy to overdo feedback so you need a strategy to limit it. This turns out to be quite simple if you follow good coding practices, even though they may seem to be hard work at first.

    I display a LOT of state information on my UI because it adds significant ease of use and confidence, so limiting the performance load it causes is important.

    I do all my button feedback (switching on and off when the button is pressed) in one place, the code that handles button pushes, knows (in a table) what every button is for, and whether it needs feedback.

    I do all my state feedback (all displaying of state to the tp - colours, captions, etc) in one place - that is, in a series of related routines called "RefreshThisThatAndTheOther". This makes state display very easy to control. It also BTW means that state display is potentially heavy going because you have to update absolutely everything dynamic about eg the VCR at the same time.

    I generally call all of the Refresh routines from only one place, in a routine that runs through an array of flags to see whether a given area needs a refresh. The review routine runs every half a second or so - there doesn't seem to be a need to display state faster than that - your mileage may differ. This caps the refresh load and ensures that you can never swamp your system with state refresh.

    At the end of every piece of code that could change the state which is being displayed, I call a routine which switches on the appropriate flag. It doesn't matter how often this happens, because it just "leaves a note" for another routine to do the work (just once) later. This seems to be an important method for a lot of NetLinx coding.

    Of course some Refresh routines need to be called directly by the code that "knows" an update is required right now. An example is the line of text that grows as you key in a phone number on a keypad.

    And finally, in a multi-touchpanel system, all commands to the UI go via a single piece of code that knows whether each touchpanel exists and is awake, and send the updates only to those which are. This might seem hard work, but once again the practice of doing a given thing in only one place can be very helpful.

    Just last week I realised that I needed to have a random mixture of both G3 and G4 panels in a given system; writing the code to send the right commands to each type of panel only took a few hours, because all outgoing commands already went through one routine.
  • adysadys Posts: 395
    yuri wrote:
    you could do something like this:

    make a dev array with all the touchpanels in your system.
    Then, somewhere in your code, you could do this:
    BUTTON_EVENT[allTPs, securityButton]
    {
      push:
      {
        local_var integer i
        i = get_last(allTPs)
    
        //have a function update security stuff
        updateSecurity(i)
    
        //send tp to page
        SEND_COMMAND allTPs[i], 'PAGE-Security'
      }
    }
    
    

    where allTPs is your dev array, and securityButton is your channel code :)

    hope this helps abit, i think it's the best way to update information
    thanks Yuri :)
  • adysadys Posts: 395
    GSLogic wrote:
    Older style programming used the DEFINE_PROGRAM for button feedback and such. In very large systems this can slow things down, so I only send feedback to panels needing information. If it's a smaller system 1-4 panels, I'm not sure I'd even worry about it, but it is a good habit to get into.
    Thanks, I will try to avoid this issue.
    I notice this kind of programming in a Design Xpress code.
  • adysadys Posts: 395
    It's quite easy to overdo feedback so you need a strategy to limit it. This turns out to be quite simple if you follow good coding practices, even though they may seem to be hard work at first.

    I display a LOT of state information on my UI because it adds significant ease of use and confidence, so limiting the performance load it causes is important.

    I do all my button feedback (switching on and off when the button is pressed) in one place, the code that handles button pushes, knows (in a table) what every button is for, and whether it needs feedback.

    I do all my state feedback (all displaying of state to the tp - colours, captions, etc) in one place - that is, in a series of related routines called "RefreshThisThatAndTheOther". This makes state display very easy to control. It also BTW means that state display is potentially heavy going because you have to update absolutely everything dynamic about eg the VCR at the same time.

    I generally call all of the Refresh routines from only one place, in a routine that runs through an array of flags to see whether a given area needs a refresh. The review routine runs every half a second or so - there doesn't seem to be a need to display state faster than that - your mileage may differ. This caps the refresh load and ensures that you can never swamp your system with state refresh.

    At the end of every piece of code that could change the state which is being displayed, I call a routine which switches on the appropriate flag. It doesn't matter how often this happens, because it just "leaves a note" for another routine to do the work (just once) later. This seems to be an important method for a lot of NetLinx coding.

    Of course some Refresh routines need to be called directly by the code that "knows" an update is required right now. An example is the line of text that grows as you key in a phone number on a keypad.

    And finally, in a multi-touchpanel system, all commands to the UI go via a single piece of code that knows whether each touchpanel exists and is awake, and send the updates only to those which are. This might seem hard work, but once again the practice of doing a given thing in only one place can be very helpful.

    Just last week I realised that I needed to have a random mixture of both G3 and G4 panels in a given system; writing the code to send the right commands to each type of panel only took a few hours, because all outgoing commands already went through one routine.


    Thanks Mark

    I thought about making a module for each device on the network, to make some order in my program.

    I have about 150 devices, if I will put all the buttons events in one place it will make a huge program, don't you think?
  • DHawthorneDHawthorne Posts: 4,584
    adys wrote:
    Thanks Mark

    I have about 150 devices, if I will put all the buttons events in one place it will make a huge program, don't you think?

    There is a limit to the event table size. Break your events up by function. You can have somewhere around 1024 table entries, anything higher than that will simply not work.
  • adysadys Posts: 395
    I thinking about making one program for each device, that will hold all the info , events, statuses etc etc


    simple question:

    Is there any limitation on Data access from program to program?

    I saw the the included programs know about the main program data, does any program can acess other program as well?

    I mean data arrays and function.

    for example if I want my program X to call function of program Y where both X and Y are include programs of the main program.
  • adys wrote:
    I thought about making a module for each device on the network, to make some order in my program.

    I have about 150 devices, if I will put all the buttons events in one place it will make a huge program, don't you think?

    You most certainly should have one module per device except perhaps for trivial devices eg a relay-controlled switch, where the module would perhaps have only one line of "active" code. I could spend all day explaining why, and others have done so elsewhere, for now let's say that using modules is NetLinx programming best practice.

    I can't see how putting all the button events in one place makes for a bigger program than spreading them around.
  • adys wrote:
    I thinking about making one program for each device, that will hold all the info , events, statuses etc etc

    Is there any limitation on Data access from program to program? I saw the the included programs know about the main program data, does any program can acess other program as well? I mean data arrays and function.

    for example if I want my program X to call function of program Y where both X and Y are include programs of the main program.

    First, a NetLinx controller can have only one program. So I'm going to assume that you mean "module" where you write "program" and I shall ignore the term "include" as that implies something else.

    Yes there is a significant limitation on data access from one module to another. All shared data must be passed from the mainline into each module via its header. Any type of variable may be passed except for structures that oyu have defined yourself (which is a serious nuisance.)

    If you need to share lots of minor (and volatile) items of data between modules, I recommend using a general-purpose array of (eg) 1000 integers and use a set of "public" constants as subscripts into the array. That way, when you add an item, you need only add a constant to the include (a highly reliable and simple process) rather than modify the header of every module and every instance in the mainline (a somewhat unreliable and arduous process.)

    Note however the whole point about modules is that they hide data which is not relevant outside the module. This is a GOOD THING and if one module needs to ferret about inside another module's underwear you may have your module structure wrong. The obvious exception is the control module for a given room, which needs to tell lots of device modules what to do, and may also need to see detailed status information from inside the module. Good practice says to expose this in a controlled manner through a status array such as that described above.

    Share "public" constants and other static data eg configuration flags by having a common include in every module containing only that information.

    Share module-independent standard functions by creating another include containing all of them and include it in every module.

    Communicate between modules using button pushes or send_commands. I have a wrap routine that wraps a standard collection of arguments into a string to send_command to another module, and an unwrap routine to dig the arguments out of the string at the other end.

    I use button pushes for things like the control module telling the VCR transport to stop playing as the system is closing down. I use send_commands for almost anything else.

    Here is a slight simplification of the module header I use for ALL device driver modules. I don't necessarily use all of this stuff in all modules, I just make it available and see what transpires:
    module_name = 'mCameraSerial'          (
      integer mModuleNumber                , (* Each module has a unique number *)
      char    sModuleName[]                , (* And a unique name *)
      char    sModelName[]                 , (* Some modules handle a variety of different device models *)
      dev     vControls[]                  , (* Array of all control devices so this module can send commands to other modules *)
      dev     dDevice                      , (* Physical device to which the equipment is connected *)
      dev     dTouchpanel                  , (* Incoming pushes from a touchpanel or commands from another module *)
      integer nConfig[]                    , (* Generic array of persistent configuration information *)
      integer nStateRequested[]            , (* Generic array of states requested of this module *)
      integer nStateReported[]             , (* Generic array of states reported by this module *)
      integer nSystemStates[]              ) (* Generic array of system-wide state information eg System Power On/Off *)
    
    (* Constants like True = 1 and False = 0 *)
    #include 'iGenericConstants.axi' 
    (* Constants describing this installation *)
    #include 'iBuildConstants.axi'
    (* Standard routines used everywhere *)
    #include 'iStandardFunctions.axi'
    
  • adysadys Posts: 395
    Thanks for your detailed answer

    That was helpfull

    Ady
  • mkipemkipe Posts: 10
    DHawthorne wrote:
    There is a limit to the event table size. Break your events up by function. You can have somewhere around 1024 table entries, anything higher than that will simply not work.

    Is 1024 for the entire application? It seems like it would be easy to run out with just a few TPs and remotes. If I do an array of buttons for a button event, does each one count or does this count as 1 entry in the table?
  • Jeff BJeff B Posts: 37
    yuri wrote:
    you could do something like this:

    make a dev array with all the touchpanels in your system.
    Then, somewhere in your code, you could do this:
    BUTTON_EVENT[allTPs, securityButton]
    {
      push:
      {
        local_var integer i
        i = get_last(allTPs)
    
        //have a function update security stuff
        updateSecurity(i)
    
        //send tp to page
        SEND_COMMAND allTPs[i], 'PAGE-Security'
      }
    }
    
    

    where allTPs is your dev array, and securityButton is your channel code :)

    hope this helps abit, i think it's the best way to update information


    I don't see the need for the local var in this code. BUTTON.INPUT.DEVICE Holds the D:P:S of the touch panel were the button was pressed. All you need to send is:

    SEND_ COMMAND BUTTON.INPUT.DEVICE, 'PAGE-Security'
  • DHawthorneDHawthorne Posts: 4,584
    Jeff B wrote:
    I don't see the need for the local var in this code. BUTTON.INPUT.DEVICE Holds the D:P:S of the touch panel were the button was pressed. All you need to send is:

    SEND_ COMMAND BUTTON.INPUT.DEVICE, 'PAGE-Security'

    Many times it is infinitely more convenient to work with the index of the array rather than the actual button channel. This allows you to set up lookup tables and any number of other handy structures to work with your data.
Sign In or Register to comment.