Home AMX User Forum AMX General Discussion

1 controller 5 panels, 5 rooms

Hi,

Looking on some information on how to go about programming a system with 5 rooms being controlled from 5 panels in one master controller. All devices are the same in each room.

Instead of using the same code 5 times i.e. tp1 tuner1 tp2 tuner2 is i possible to have the button press know which panel its from and which device to control from one sequence of button presses?

Regards,

Noel

Comments

  • mpullinmpullin Posts: 949
    Yes, quite possible, declare an array of DEVs with all the touchpanels in there, then declare another array of DEVs for every kind of device you have, using the same order your touchpanels are in. Using the magic of GET_LAST, your program almost writes itself :D
  • nds2006nds2006 Posts: 10
    1 controller 5 panels, 5 rooms

    thanks for the replay

    Totally new to all this stuff like devs etc, would you have a quick example at hand that you can post?

    Any help appreciated

    Regards,

    Noel
  • mpullinmpullin Posts: 949
    Sure. Something like this
    DEFINE_VARIABLE // dev arrays
    DEV arrTP[] = {dvTP1,dvTP2,dvTP3,dvTP4,dvTP5}
    DEV arrDVD[] = {vdvDVD1,vdvDVD2,vdvDVD3,vdvDVD4,vdvDVD5}
    
    DEFINE_VARIABLE // touchpanel buttons
    // ...
    INTEGER butDVD_PLAY = 43
    INTEGER butDVD_PAUSE = 44
    // ...
    
    DEFINE_EVENT
    BUTTON_EVENT[arrTP,butDVD_PLAY]{
       push:{
          SEND_COMMAND arrDVD[GET_LAST(arrTP)], 'TRANSPORT:PLAY' // plays the DVD in the room of the touchpanel that was used to create this event
       }
    }
    
  • nds2006nds2006 Posts: 10
    Thanks, can see now whats happen with that

    Cheers

    Noel
  • AuserAuser Posts: 506
    nds2006 wrote: »
    Looking on some information on how to go about programming a system with 5 rooms being controlled from 5 panels in one master controller.

    Another approach would be to write a module which handles all of the control you need in each area and then to declare 5 instances of the module in your program, the idea being that you pass the panel device for the room, source and display devices for that room, etc. as parameters to the modules. This tends to work well in scenarios where you have roaming panels that can take control of different rooms and for rooms with operable walls that can be joined and subsequently separated.
  • jjamesjjames Posts: 2,908
    All I can say is: lookup tables. For multiroom . . . no, wait . . . for every job I do, I use many, many different lookup tables. Here's a brief overview of different lookup tables I use:

    Sorted by room -
    Cable boxes, DVD, VCR, TVs, etc; any device - which index in an array does the zone use? If it can control more than one device, it's most likely controlling a different zone.

    Sorted by source -
    Inputs; tv power (on or off??), audio source, heck - you could even do volume levels dependent on the source.

    Then of course, the panels - they need to know which zone they're controlling. So make a list of zones that it CAN control. Make a button event to where they can select which room it is controlling and store that in a variable. Then, use that variable in the lookup table. For instance - if I need to send a command out to a cable box, any panel in my system can use this single command which is part of my basic controls portion of my code (play, stop, pause, channel up, etc.):
    SEND_COMMAND dv_CAB[nCABLE_DEV_MAP[nPNL_AV[nIND]]],"'SP',nBTN"
    
    Where nCABLE_DEV_MAP is my look up table, nPNL_AV is my variable that tells me which panels are controlling which zones, and nIND is which panel the button event is registered to. nBTN is the BUTTON.INPUT.CHANNEL from the button event which in turn is mapped to my IR file. I even wrote up the commands for serial devices that we use in nearly every job (Integra CDC-3.4) into a look up table, instead of the code above, it'd be something like this:
    SEND_STRING dv_CDC[nCD_DEV_MAP[nPNL_AV[nIND]]],"CD_COMMANDS[nBTN],CR"
    
    . And if nBTN is one, then I send play, two - stop, three - pause, etc. etc.

    This makes a truly expandable system, to where you can add zones later on should the client decide to add 3 more rooms of audio, and cable, or even add three more panels. Also, it's very easy to use this type of code from one job to another, regardless of how many panels or zones there are. My advice - keep it expandable. I know there are plenty of ways to do this, and this is just one of them, but I think we would all agree that keeping a system expandable is very important when doing a job. Going back to some of my older jobs, I cringe at having to change something - they were practically coded in stone. Keeping a system expandable will save you time, money and headaches when something simple needs to be changed and you realized that you only wrote code for 5 rooms and 5 panels.
  • nds2006nds2006 Posts: 10
    thanks for the all the ideas, I am only starting out on this road of AMX programming, not up to creating modules yet and look up tables, but hopefully will progress to a better level as time goes by
  • sling100sling100 Posts: 123
    Hi

    Old thread I know, but no point in reinventing the wheel!

    Jeremiah - can you help me out and expand on your lookup table code for this example? I understand the 'one room one touchpanel' idea (ie PULSE DVDArray[nTPRef]), but I get a bit lost when it comes to controlling other areas and I need to do exactly this - ie 7 roaming panels controlling any of the 7 zones

    Thanks

    Simon
  • jjamesjjames Posts: 2,908
    sling100 wrote: »
    Jeremiah - can you help me out and expand on your lookup table code for this example? I understand the 'one room one touchpanel' idea (ie PULSE DVDArray[nTPRef]), but I get a bit lost when it comes to controlling other areas and I need to do exactly this - ie 7 roaming panels controlling any of the 7 zones.

    Simon, not a problem. Here's where I feel the real power in having flexible code is. And forgive me if I explain this either a bit to "complicated" or "too simple" as I've never really had to go into further detail (either no one was interested or they already got it.) Anyway.....

    Okay, so we've got 7 zones, with 7 touch panels. Going off of some of the examples in my previous post, we need to know some of the very basics. First, what zones do we have? Second, what sources are there? Third, what devices are there to control? You get the idea, all of the knowns need to be spelled out in their own arrays. So - all the cable boxes, just throw them into an array.
    DEV dv_Cable[]=
    {
    	 dvCAB_MGR
    	,dvCAB_MBR
    	,dvCAB_KIT
    	,dvCAB_FAM
    }
    

    So now, we need to know which zones control which cable boxes. And right now, we're loading the defaults when we do all this.
    INTEGER nCAB_DEV_MAP[]=
    {
    	 1	// Main Great Room
    	,2	// Master Bedroom
    	,3	// Pool
    	,3	// Kitchen
    	,4	// Family Room
    	,2	// Media Room
    	,1	// Loft
    }
    

    It's important to keep the order of your ZONES the same as their values. Since we use Autopatch switchers in all of our jobs, the zones in code refer to the output on the switcher. Anything NOT on the switcher (i.e. single media room that has nothing to do with anything on the Autopatch, is added at the end, so in an 16x16 switcher, it'd become zone 17.)

    You'll also want to set up an array of buttons that - again, in order of zones just to make it easy - represent the zone. So when they hit the 3rd button in the array, they're controlling now the 3rd zone, which in our example would be the pool. Now that the panel is controlling zone three, it gets all of the values for the pool.

    So, with the previous posts example - a control command would look like this:
    DEFINE_CONSTANT		// Constants - Dev Arrays
    DEV dv_Cable[]=
    {
    	 dvCAB_MGR
    	,dvCAB_MBR
    	,dvCAB_KIT
    	,dvCAB_FAM
    }
    
    INTEGER nCAB_DEV_MAP[]=
    {
    	 1	// Main Great Room
    	,2	// Master Bedroom
    	,3	// Pool
    	,3	// Kitchen
    	,4	// Family Room
    	,2	// Media Room
    	,1	// Loft
    }
    
    DEFINE_VARIABLE
    
    INTEGER nPNL_AV[7] = 
    {
    	 1 // Main Great Room
    	,2 // Master Bedroom
    	,3 // Pool
    	,4 // Kitchen
    	,5 // Family Room
    	,6 // Media Room
    	,7 // Loft						
    }
    
    DEFINE_EVENT
    BUTTON_EVENT[dv_TP,nMISC_BTNS]
    {
    	PUSH:
    	{
    		STACK_VAR INTEGER nIND;
    		STACK_VAR INTEGER nBTN;
    		nBTN = BUTTON.INPUT.CHANNEL;
    		nIND = GET_LAST(dv_TP);
    		
    		// snippet for controlling the cable box
    		SEND_COMMAND dv_CAB[nCABLE_DEV_MAP[nPNL_AV[nIND]]],"'SP',nBTN"
    		
    		// If nIND = 3, then things could look like this:
    		// SEND_COMMAND dv_CAB[nCABLE_DEV_MAP[3]],"'SP',nBTN"
    		// which could be SEND_COMMAND dv_CAB[3],"'SP',nBTN";
    		// which could be SEND_COMMAND dvCAB_KIT,"'SP',nBTN";
    		
    		// dv_TP is your array of touch panels, usually in order of device number
    		// but really has no need to be in any particular order.
    		
    		// nPNL_AV is set when the panel (nIND) was given it's initial value when
    		// we defined it in the DEFINE_VARIABLE section.
    		
    		// nCABLE_DEV_MAP was defined early, on a per zone basis. We can have more cable boxes
    		// per zone (i.e. a lower sports bar with 3 cable boxes) by adding another dimension
    		// to the array. So instead of dv_CAB[ZoneMap[Zone]], it woudl be dv_CAB[ZoneMap[Zone]][BoxMap[Zone]]
    		
    		// dv_CAB was also defined earlier as just an array of cable boxes with no particular order.
    		// nCABLE_DEB_MAP sorts dv_CAB out.
    		
    		// nBTN is BUTTON.INPUT.CHANNEL;
    		
    		// End result - your DEVICE arrays can be in any number, your MAPS just connect the dots.
    	}
    }
    

    Set up your DEV arrays, and your device maps for each type of device (even if there is just one) and you'll be set to add more panels, more devices, more zones . . . really more of anything in the future.

    Shoot me a PM later if you would like for me to call you (if you're in the States) and try to explain this a bit more sometime this afternoon.
  • Question....

    What if you needed to control multiple cable boxes from the same and multiple TPs?
  • jjamesjjames Posts: 2,908
    Chevyman78 wrote: »
    What if you needed to control multiple cable boxes from the same and multiple TPs?

    Then instead of looking up the table, look at a variable.
    SEND_COMMAND dv_CABLE[[COLOR=RED]nCableSelect[/color][nPNL_AV[nIND]],"'SP',nBTN";
    
    nCableSelect would be set in another button event (or function) to determine which box is used.

    What I actually do is for IR devices create a DEV variable named IR_DEVICE, and make it the size of however many zones we have. (ex. VOLATILE DEV IR_DEVICE[MaximumZones]) and in the main button event that controls the sources, do a SWITCH on which source we're using, stack all the IR sources and just send the command to the IR_DEVICE instead of dv_CABLE, dv_DVD, or dv_VCR whatever. Then I have another button event that selects and sets which cable box (or VCR, DVD, etc.) we're to use and then calls a function that does anything needed to view that box (i.e. change TV inputs, audio inputs, etc.) and also populate the IR_DEVICE variable.
  • vegastechvegastech Posts: 369
    Question on the nPNL_AV array: Is that supposed to define the number of panels in the project, or the number of zones, or both?
  • jjamesjjames Posts: 2,908
    vegastech wrote: »
    Question on the nPNL_AV array: Is that supposed to define the number of panels in the project, or the number of zones, or both?

    nPNL_AV's length is the number of panels in the system. Each index in a zone's value.

    I define all of my zones as constants (as I'm sure most do) for readability and in the case I need to do anything special in a zone; this makes it easy to define your nPNL_AV array. It can be a large array or a small array - doesn't matter. Here's a quick copy from the job I'm at right now.
    VOLATILE INTEGER nPNL_AV				[nPNL_MAX]=
    {
    	 nZONE_DTR_MBR					//  1
    	,nZONE_MBATH                                    //  2
    	,nZONE_DTR_HEARTH                               //  3
    	,nZONE_MGS				        //  4
    	,nZONE_GUEST_BATH                               //  5
    	,nZONE_EXR                                      //  6
    	,nZONE_KITCHEN                                  //  7
    	,nZONE_DTR_LOOK                                 //  8
    	,nZONE_BASKETBALL                               //  9
    	,nZONE_DINING                                   // 10
    	,nZONE_DTR_FAM                                  // 11
    	,nZONE_GARAGE                                   // 12
    	,nZONE_OFFICE_SUE                               // 13
    	,nZONE_LOGGIA                                   // 14
    	,nZONE_STUDY                                    // 15
    	,nZONE_HALL_UPPER 	                        // 16
    	,nZONE_UTILITY_ROOM                             // 17
    	,nZONE_DTR_MBR                                  // 18 -- R4s Start Here!
    	,nZONE_TERRACE_MBR                              // 19
    	,nZONE_DTR_HEARTH                               // 20
    	,nZONE_MGS                                      // 21
    	,nZONE_EXR                                      // 22
    	,nZONE_KITCHEN                                  // 23
    	,nZONE_DTR_LOOK                                 // 24
    	,nZONE_CABANA                                   // 25
    	,nZONE_DTR_MED                                  // 26
    	,nZONE_FUTURE_RM                                // 27
    	,nZONE_TV_SNUG                                  // 28
    	,nZONE_WINE                                     // 29							
    }                                             
    
  • a_riot42a_riot42 Posts: 1,624
    Chevyman78 wrote: »
    What if you needed to control multiple cable boxes from the same and multiple TPs?

    Typically I will write a module that will control an arbitrary number of cable boxes from an arbitrary number of touch panels. Any or all panels can then control any or all devices, When adding either cable boxes or touch panels to a system, the only thing that needs to change is the array of touch panels or the array of cable boxes.

    A company I previously worked for used to do it so that you needed a module per device-panel pair, but that got silly with a house using 25 panels to control 15 global sources. That would have required 25 x 15 = 375 modules! Going from dozens of modules to 1 really makes the system much more snappy and responsive I have found. The bottleneck then becomes how quickly the devices can respond to commands, but that's a different problem.
    Paul
  • jjames wrote: »
    Then instead of looking up the table, look at a variable.
    SEND_COMMAND dv_CABLE[[COLOR=RED]nCableSelect[/color][nPNL_AV[nIND]],"'SP',nBTN";
    
    nCableSelect would be set in another button event (or function) to determine which box is used.

    What about a situation with one room, three TP's, and two cable boxes? Is nCableSelect an array? If TP 3 wanted to control Tuner 1, I'm lost.
    SEND_COMMAND dv_CABLE[[COLOR=RED]nCableSelect[/color][3]],"'SP',nBTN";
    

    nCableSelect could only be a 1 or a 2. In the event that Tuner 1 needed to be controlled, I would need to send the command to dv_CABLE[1]. I can make nCableSelect by a button push, but I don't understand how you are doing it in the array. Doing it the way I had been doing it, the TP would have a "TUner 1" button and a "Tuner 2" button, nCableSelect would be set by whatever button they select. In my particular situation, I need to know which TP is controlling which tuner for control purposes. So, if TP 1 is controlling Tuner 2 and presses the channel up button, Tuner 2 will increment. Likewise, if TP 3 is controlling Tuner 1, Tuner 1 will increment. In a nutshell, if a TP presses channel up, the system needs to verify which TP pressed the button, which tuner they are controlling, and act accordingly. The simple way would be to create a dvTUN1_TP and dvTUN2_TP. But, I am trying to get away from that habit. I would like to understand how your example is working. If for example 1 TP had access to both tuners and each of the other ones only had access to one tuner, this would be very helpful. Or if more tuners were added to the system, it would not take very much on my part to update the code.
  • jjamesjjames Posts: 2,908
    Sure - let's look at each variable's value and function.

    nCableSelect[]
    This variable's (or constant's) maximum LENGTH is the number of rooms, or zones you have. The VALUE of nCableSelect[x] is the index in your cable box array.

    How you divvy up a zone, or room is up to you - but I look at the maximum number of audio outputs on our switcher and use that as the minimum max number of zones I'll have; then I take in to consideration stand-alone rooms such as rooms with a receiver. So - for instance, if we have an 18x18 - I've got at least 18 zones, and if I had a receiver that does not hooked up to our switcher, I now have 19 zones. (This is even if we're only utilizing 5 outputs on the 18x18 - you can grow you know!!) So, the max length is number of zones; minimum is obviously one - but still treat it as an array in case you do need to add more zones.

    nPNL_AV[]
    The maximum LENGTH is the number of panels in the system. The VALUE is the zone / room number in the system.

    This value is set either at define_start or in your define_variable section - but it CAN change, thus giving every panel the ability to control any zone.

    dv_CABLE[]
    This one should be obvious, but for the sake of continuity in explaining things... This is a device array that holds your cable boxes. No max, just the cable boxes.

    So - let's populate this stuff and see how it works.

    Max rooms 1
    Max panels 3
    Max Cable boxes 2

    nPNL_AV[1] = 1 // Controlling zone 1
    nPNL_AV[2] = 1 // Controlling zone 1
    nPNL_AV[3] = 1 // Controlling zone 1

    dv_cable[1] = dvCab1
    dv_cable[2] = dvCab2

    Somewhere in the code, either in define_start, a function that calls the powering up of a room, or if you treated this as a constant - these values need be set somewhere - you'll see this.

    nCableSelect[1] = 2 // Zone 1 is controlling cable box 2

    So, when the button event to fire off at a cable box, we need to ensure a few things:
    1) A panel is controlling a zone
    2) A zone is controlling a cable box

    Now, panel 1 (obviously controlling zone 1) pressed channel up in its cable box source. Panel one controls zone 1, zone one is controlling cable box 2.

    nIND = GET_LAST(dv_TP);
    nBTN = BUTTON.INPUT.CHANNEL;

    (nIND actually equals 1, and nBTN equals 22)
    TO[ dv_CABLE[nCableControl[nPNL_AV[nIND]]],nBTN]

    Breaking it down & substituting variable names with variable values
    nIND = 1
    nPNL_AV[nIND] = 1
    nBTN = 22
    TO[dv_CABLE[nCableControlcolor=red]1[/color],22]

    And one more step
    nCableControl[1] = 2
    to[dv_cablecolor=red]2[/color,22]

    And again
    to[dvCab2,22]

    End result - you can change these values on the fly anywhere in code, and it can change how things works. By treating things as an array (even if the length is one), you can always go back 6 months from now, and increase the size of your arrays, and not have to change any of the control code - just the definitions of dv_cable, and if the new zone defaults to the new panel.

    Hopefully this helps. I use this train of thought with my structures now (referenced in another thread), but the principle is the same - I've just broken it down even more treating cable boxes as objects with attributes (i.e. the input number on the switcher, which input is used on which tv for a particular cable box.) The idea isn't new - I'm just getting around to it. ;)
  • Thanks

    YOu were able to beat me to the punch. When I edited my original question, an idea dawned on me. Not what you posted ( I like yours better), but I think I was following the same route, or at least in the same city. lol. I was thinking about creating a structure and putting nCableSelect in it. Depending on which TP was controlling which tuner, that variable would be stored to and called from the structure. Then I could do something like:
    DEFINE_TYPE
    STRUCTURE _sCable_Selected_Box
    {
           INTEGER nCableSelect
    }
    
    DEFINE_VARIABLE
    _sCable_Selected_Box  _which_one[3]
    
    
    DEFINE_EVENT
    BUTTON_EVENT[some button]
    {
           PUSH:
           {
                  _which_one[nIND].nCable_Select = the cable box that TP is controlling
           }
    }
    
    

    I think I skipped a few steps somewhere, but I hope you get the idea. Not as sexy as yours though. Thanks for the reply.
  • OK, I've got it ( I think). I have 3 TP's and 2 tuner boxes. Each TP needs to have the ability to be able to control both tuner boxes. So if someone is sitting in front of TP1 and selects Tuner 2, that needs to be the tuner that is getting controlled, likewise if the select Tuner 1, that one needs to be controlled. Same for the other 2 panels. When I am setting up the initial default values for nPNL_AV, I can use 1 for all three:
    INTEGER nPNL_AV[3] = 
    {
    	 1,  // Zone 1
    	 1,  // Zone 1
    	 1   // Zone 1				
    }
    

    This would give all 3 panels control over zone 1. (I still don't grasp the concept of zones when using multiple switchers in one room, but I'll get it eventually.) Then, using your example, this:

    TO[ dv_CABLE[nCableControl[nPNL_AV[nIND]]],nBTN]

    will check which panel pushed a button, which zone that panel is controlling, and which device that zone is controlling. In order to make all three panels able to control either tuner, whenever a certain panel selects which tuner they want to control, I need to update that panel's index in nPNL_AV. I can put the tuner select buttons in an array use a GET_LAST, and update that particular panel's zone number in the nPNL_AV array. Correct?
  • jjamesjjames Posts: 2,908
    Almost - what you need to update when switching tuners is the nCableSelect. Example on that:
    BUTTON_EVENT[dv_tp,cable_select_btns]
    {
      push:
      {
        stack_var integer i_index;
        stack_var integer i_panel;
        i_panel = get_last(dv_tp); // get which panel used this button event
        i_index = get_last(cable_select_btns); // get which tuner we want
    
        nCableSelect[nPNL_AV[i_panel]] = i_index; // Assign which tuner goes to that panel's zone.
    
        // Do anything else such as switching video, or pages, or whatever you want when the user changes the tuner
      }
    }
    

    nPNL_AV is a place holder to see WHICH ZONE THE PANEL is controlling. This value changes if / when you add more zones. So in an 18 zone system, you can have all panels access the same zone, or different zones.

    Can you explain by what you mean when you say multiple switchers in one room? What equipment are you using for audio switching?
  • jjames wrote: »
    Can you explain by what you mean when you say multiple switchers in one room? What equipment are you using for audio switching?

    The room has a 32x32 Extron Crosspoint for hi res sources and a 24x24 Extron MAV for low res sources. In order to display the low res sources, the signals are passed through scalers, input into the hi res switch and displayed via projectors. This room is the very first program I ever wrote. If you look back over my questions from a few years ago, I talked extensively about this particular room. New devices have been added and now I am stuck going back over lines and lines of code to figure out a way to implement these devices. Since everything was hard coded, this is taking forever. I figured since I needed to re-do it, I might as well do it properly and also make provisions for myself or the next guy should something else come along. That was how I got on the zones, and event tables topics. I was trying to make as much of the code table driven as possible. Right now, the code is a mess. Just to give you an example, I have 36 panels that I created back then. I made a panel for EVERYTHING. That way I did not have to track any variables or anything. This was a nightmare. I totally ditched everything and started from scratch. So far, I only have 3 touchpanels, 56 buttons, and have eliminated over 300 lines of code. I had IF tables long enough to write a book. I don't know what I was thinking back then, but if I could go back in time, I would smack myself silly for doing something so crazy.
Sign In or Register to comment.