1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. If you had a PIAF Forum account in the vBulletin days, log in with your old credentials. Otherwise, sign up again and we'll get you back in business as soon as we can.
  3. A serious FreePBX vulnerability has been reported. Update your Framework Module immediately. Click here for details.
  4. Critical FreePBX vulnerability! Update your server immediately. Details here.

SOLVED (WORKING) Direct Parking to Parking Slots ("valet parking")

Discussion in 'Help' started by nicknomo, Mar 12, 2014.

  1. nicknomo Happy-IT-Guy

    Basically, I wanted to give people the ability to park calls in parking spot positions of my choosing ("valet style" parking). These would often be represented by BLFs on the phone, and someone like an operator could quickly transfer calls to free slots and announce them instead of having the parking lot position read back to them. This can replicate the functionality of a key system, to some degree, where you have LINE keys.

    There were many many solutions to this online, and while none of them worked for me, I was able to use them to tweak things. So, credit goes to all of those who posted their solutions. This is tested and working for me (using Elastix 2.4, Asterisk 11.5, FreePBX 2.8). Since it almost entirely involves using the Asterisk dial plan, I'm pretty sure it will work with almost all Asterisk 11 / FreePBX distros.

    edit: THIS IS NOW TESTED AND WORKING WITH FREEPBX 2.11

    I believe I've accounted for most situations. If a transfer comes into an occupied parking spot, it gets shot back. If someone dials into the parking spot, they can pick up a call, provided the extension is in use. The only real non-standard thing I can see is that if the extension isn't in use, and someone dials in, they can park themselves. I suppose I could've added a few more lines to account for this, but I didn't think it was really worth the extra complexity. If you park yourself, you can just hang up.

    I hope this is useful to those who were in my position.

    Instructions:
    note: file editing can be done by using the config editor in PBXIAF or Elastix


    1) If your version of FreePBX is 2.8 or earlier, turn off parking in FreePBX. We will be using a custom dialplan instead. If its a later version of FreePBX, turn off hints.

    2) Edit features_general_custom.conf add this:
    Code:
    parkedcalltransfers = caller
    parkedcallreparking = caller
    parkext=700
    parkpos=701-705
    context=parkedcalls
    parkingtime=60
    pickupexten=*8
    parkext_exclusive=no
    ;Enter any other desired parking lot variables.
    ;See list of variables here
    ;https://wiki.asterisk.org/wiki/display/AST/Asterisk+12+Configuration_res_parking
    
    3) Edit extensions_custom.conf , and

    a) insert this under the [from-internal-custom] section
    Code:
    include => park-hints2
    
    b) at the bottom of the file, add the following
    note: IF you use 4 digit extensions, change this:
    exten => _70[12345],n,set(extLeng=3).
    so that it says this:
    exten => _70[12345],n,set(extLeng=4).


    Code:
    [park-hints2]
    include => park-hints-custom
    exten => 701,hint,park:701@parkedcalls
    exten => 702,hint,park:702@parkedcalls
    exten => 703,hint,park:703@parkedcalls
    exten => 704,hint,park:704@parkedcalls
    exten => 705,hint,park:705@parkedcalls
    exten => _70[12345],1,Set(PARKINGEXTEN=${EXTEN})
    ;start state debugging info
    exten => _70[12345],n,NoOP(Park in parkinglot: ${PARKINGEXTEN})
    exten => _70[12345],n,NoOP(Checking for parking lot: park:${EXTEN}@parkedcalls)
    exten => _70[12345],n,NoOP(Parking Lot State: ${DEVICE_STATE(park:${EXTEN}@parkedcalls)})
    ;end state debugging info
    ;IF YOU HAVE TWO DIGIT USER EXTENSIONS, THIS WILL NOT WORK FOR YOU!
    ;IF YOU USE 4 DIGIT EXTENSIONS, SET extLeng=4  !!!!!!!!!
    exten => _70[12345],n,set(extLeng=3)
    ;If the line is not in use, we park it.  Otherwise, we return the call to whomever transferred it
    exten => _70[12345],n,GotoIf($[ ${DEVICE_STATE(park:${EXTEN}@parkedcalls)} =NOT_INUSE ] ?PARK,1)
    ;Start Busy/non-park debugging for non park scenario
    exten => _70[12345],n,NoOP(Park is INUSE: ${EXTEN})
    exten => _70[12345],n,NoOP(Failed park: ${EXTEN}@parkedcalls)
    exten => _70[12345],n,NoOP(Transferer of Park: ${BLINDTRANSFER})
    ;Stop Busy/non-park debugging for non park scenario
    exten => _70[12345],n,GotoIf($[ "${BLINDTRANSFER:4:${extLeng}}" = "" ] ?PICKUPPARK)
    exten => _70[12345],n,NoOP(Transferred call, sending back to: ${BLINDTRANSFER:4:${extLeng}} )
    exten => _70[12345],n,dial(local/${BLINDTRANSFER:4:${extLeng}}@from-internal,,tr)
    exten => _70[12345],n,Hangup()
    exten => _70[12345],n(PICKUPPARK),NoOP(This is an inside call, Pick up Park Extension: ${EXTEN})
    exten => _70[12345],n(PICKUPPARK),ParkedCall(${EXTEN})
    exten => _70[12345],n(PICKUPPARK),Hangup()
    ;Park The call
    exten => PARK,1,Park(,from-internal,${BLINDTRANSFER:4:${extLeng}},,s)
    exten => PARK,n,Hangup()
    ;This is for park retrieval - it is an additional option to dialing the number directly
    ;Best if use with a "prefix" DSS key bound to **.
    exten => _**70[12345],1,NoOP(PICK UP PARKED CALL!!!!!!!!!: ${EXTEN})
    exten => _**70[12345],n,ParkedCall(${EXTEN:2})
    exten => _**70[12345],n,Hangup()
    
    and optionally, if you are using FreePBX 2.8...

    Code:
    [park-dial]
    include => park-dial-custom
    exten => t,1,Noop(Parked Call Timed Out and Got Orphaned)
    exten => t,n,Goto(ivr-3,s,1)
    exten => _[0-9a-zA-Z*#].,1,Noop(Parked Call Timed Out and Got Orphaned)
    exten => _[0-9a-zA-Z*#].,n,Goto(ivr-3,s,1)
    
    That last section is something I stole from the FreePBX generated code. You will probably want to edit this very last section of the code if you choose to use it (you don't have to!). It most likely will not work the way you want it to. It is normally found in extensions_additional.conf, but I now have it tacked to the end of extensions_custom.conf. You can enable call parking in FreePBX, set the desired behavior, and then go search for [park-dial] in extensions_additional.conf. After you find it, cut and paste it to the end of extensions_custom.conf, and disable call parking in FreePBX.
    Last edited by nicknomo, May 16, 2014
    sorvani, atsak and rjaiswal like this.
  2. atsak Guru

    Goodness you're clever.
  3. nicknomo Happy-IT-Guy


    Thanks... I really have no idea what I'm doing though. The only reason I was able to do this much was because of a few similar solutions posted by different people all over the web. I'm just standing on the shoulders of giants...

    That's why I figured it was important to post the solution. I'm sure someone will might my post in a few years and retool it to make it work with the current version of asterisk, if necessary... (good luck, people from the future!)
  4. nicknomo Happy-IT-Guy

    Ok, I added another parking lot just for kicks, in case people wanted to do more than one of these lots. Multiple parking lots can be very useful. In my example, anyone can still pick up from anyone else's lot by default.

    edit: THIS IS NOW TESTED AND WORKING WITH FREEPBX 2.11

    Multiple parking lots in asterisk seems poorly documented, but its really very easy. Additional parking lots need to be specified in features_general_custom.conf. The parking lot name must start with "parkinglot_". For instance, a second parking lot should be declared as [parkinglot_test]. In my example, I used [parkinglot_lot2]. The context should match the parking lot name, for simplicity purposes.

    When setting up the hints for a second parking lot, the hints must use the same context that we declared above. The hint would look like this: exten => 801,hint,park:801@parkinglot_lot2 .

    Finally, when making the dialplan for picking up a call in your non-default parking lot, you need to specify what lot you are picking up from. Instead of calling ParkedCall(${EXTEN}) , you need to call ParkedCall(${EXTEN}, name of your parking lot). For my example, this was ParkedCall(${EXTEN},parkinglot_lot2).

    This is really all it takes to add more parking lots to the code I described. The rest is just changing the numbers...

    Instructions:
    note: file editing can be done by using the config editor in PBXIAF or Elastix


    1) If you are using FreePBX 2.8, turn off parking in FreePBX. We will be using a custom dialplan instead. If its a later version of FreePBX, then configure the default parking lot to be a single extension outside of the ranges you are using. Turn off hints on the default parking lot. You can still use the default lot in a different range, if you really want, but if you won't be using it then its better to just put it out of sight and out of mind.

    2) Edit features_general_custom.conf add this:
    Code:
     
    [parkinglot_lot1]
    parkedcalltransfers = caller
    parkedcallreparking = caller
    parkext=220
    parkpos=221-229
    context=parkinglot_lot1
    parkingtime=60
    pickupexten=*8
    courtesytone=beep
    parkext_exclusive=no
     
    [parkinglot_lot2]
    parkedcalltransfers = caller
    parkedcallreparking = caller
    parkext=700
    parkpos=701-705
    context=parkinglot_lot2
    parkingtime=60
    pickupexten=*8
    courtesytone=beep
    parkext_exclusive=no
    
    3) Edit extensions_custom.conf , and

    a) insert this under the [from-internal-custom] section
    Code:
    include => park-hints2
    include => park-hints3
    
    b) at the bottom of the file, add the following
    note: IF you use 4 digit extensions, change both instances of:
    exten => _70[12345],n,set(extLeng=3).
    These should be change to:
    exten => _70[12345],n,set(extLeng=4).
    There is one of these statements in each parking lot section (two in total) . I've commented in all CAPS where this needs to be done in the code.

    Code:
    [park-hints2]
    include => park-hints-custom
    ; THIS IS COMMENTED OUT
    ; This is how you would still use the automated parking if you choose
    ; Since we manually park, I have it disabled.
    ;exten => 220,1,Set(CHANNEL(parkinglot)=parkinglot_lot1)
    ;exten => 220,n,Set(_PARKINGLOT=parkinglot_lot1)
    ;exten => 220,n,Park()
    ;exten => 220,n,Hangup()
    exten => 221,hint,park:221@parkinglot_lot1
    exten => 222,hint,park:222@parkinglot_lot1
    exten => 223,hint,park:223@parkinglot_lot1
    exten => 224,hint,park:224@parkinglot_lot1
    exten => 225,hint,park:225@parkinglot_lot1
    exten => 226,hint,park:226@parkinglot_lot1
    exten => 227,hint,park:227@parkinglot_lot1
    exten => 228,hint,park:228@parkinglot_lot1
    exten => 229,hint,park:229@parkinglot_lot1
    exten => _22[123456789],1,Set(PARKINGEXTEN=${EXTEN})
    ;start state debugging info
    exten => _22[123456789],n,NoOP(Park in parkinglot: ${PARKINGEXTEN})
    exten => _22[123456789],n,NoOP(Checking for parking lot: park:${EXTEN}@parkinglot_lot1)
    exten => _22[123456789],n,NoOP(Parking Lot State: ${DEVICE_STATE(park:${EXTEN}@parkinglot_lot1)})
    ;end state debugging info
    ;IF YOU HAVE TWO DIGIT USER EXTENSIONS, THIS WILL NOT WORK FOR YOU!
    ;IF YOU USE 4 DIGIT EXTENSIONS, SET extLeng=4  !!!!!!!!!
    exten => _22[123456789],n,set(extLeng=3)
    ;If the line is not in use, we park it.  Otherwise, we return the call to whomever transferred it
    exten => _22[123456789],n,GotoIf($[ ${DEVICE_STATE(park:${EXTEN}@parkinglot_lot1)} =NOT_INUSE ] ?PARK)
    ;Start Busy/non-park debugging for non park scenario
    exten => _22[123456789],n,NoOP(Park is INUSE: ${EXTEN})
    exten => _22[123456789],n,NoOP(Failed park: ${EXTEN}@parkinglot_lot1)
    exten => _22[123456789],n,NoOP(Transferer of Park: ${BLINDTRANSFER})
    ;Stop Busy/non-park debugging for non park scenario
    exten => _22[123456789],n,GotoIf($[ "${BLINDTRANSFER:4:${extLeng}}" = "" ] ?PICKUPPARK)
    exten => _22[123456789],n,NoOP(Transferred call, sending back to: ${BLINDTRANSFER:4:${extLeng}} )
    exten => _22[123456789],n,dial(local/${BLINDTRANSFER:4:${extLeng}}@from-internal,,tr)
    exten => _22[123456789],n,Hangup()
    exten => _22[123456789],n(PICKUPPARK),NoOP(This is an inside call, Pick up Park Extension: ${EXTEN})
    exten => _22[123456789],n(PICKUPPARK),ParkedCall(${EXTEN},parkinglot_lot1)
    exten => _22[123456789],n(PICKUPPARK),Hangup()
    ;Park The call
    exten => _22[123456789],n(PARK),Set(CHANNEL(parkinglot)=parkinglot_lot1)
    exten => _22[123456789],n(PARK),Set(_PARKINGLOT=parkinglot_lot1)
    exten => _22[123456789],n(PARK),Park(,from-internal,${BLINDTRANSFER:4:${extLeng}},,s)
    exten => _22[123456789],n(PARK),Hangup()
    ;This is for park retrieval - it is an additional option to dialing the number directly
    ;Best if use with a "prefix" DSS key bound to **.
    exten => _**22[123456789],1,NoOP(PICK UP PARKED CALL!!!!!!!!!: ${EXTEN})
    exten => _**22[123456789],n,ParkedCall(${EXTEN:2},parkinglot_lot1)
     
    [park-hints3]
    include => park-hints-custom
    ; THIS IS COMMENTED OUT
    ; This is how you would still use the automated parking if you choose
    ; Since we manually park, I have it disabled.
    ;exten => 700,1,Set(CHANNEL(parkinglot)=parkinglot_lot2)
    ;exten => 700,n,Set(_PARKINGLOT=parkinglot_lot2)
    ;exten => 700,n,Park()
    ;exten => 700,n,Hangup()
    exten => 701,hint,park:701@parkinglot_lot2
    exten => 702,hint,park:702@parkinglot_lot2
    exten => 703,hint,park:703@parkinglot_lot2
    exten => 704,hint,park:704@parkinglot_lot2
    exten => 705,hint,park:705@parkinglot_lot2
    exten => _70[12345],1,Set(PARKINGEXTEN=${EXTEN})
    ;start state debugging info
    exten => _70[12345],n,NoOP(Park in parkinglot: ${PARKINGEXTEN})
    exten => _70[12345],n,NoOP(Checking for parking lot: park:${EXTEN}@parkinglot_lot2)
    exten => _70[12345],n,NoOP(Parking Lot State: ${DEVICE_STATE(park:${EXTEN}@parkinglot_lot2)})
    ;end state debugging info
    ;IF YOU HAVE TWO DIGIT USER EXTENSIONS, THIS WILL NOT WORK FOR YOU!
    ;IF YOU USE 4 DIGIT EXTENSIONS, SET extLeng=4  !!!!!!!!!
    exten => _70[12345],n,set(extLeng=3)
    ;If the line is not in use, we park it.  Otherwise, we return the call to whomever transferred it
    exten => _70[12345],n,GotoIf($[ ${DEVICE_STATE(park:${EXTEN}@parkinglot_lot2)} =NOT_INUSE ] ?PARK)
    ;Start Busy/non-park debugging for non park scenario
    exten => _70[12345],n,NoOP(Park is INUSE: ${EXTEN})
    exten => _70[12345],n,NoOP(Failed park: ${EXTEN}@parkinglot_lot2)
    exten => _70[12345],n,NoOP(Transferer of Park: ${BLINDTRANSFER})
    ;Stop Busy/non-park debugging for non park scenario
    exten => _70[12345],n,GotoIf($[ "${BLINDTRANSFER:4:${extLeng}}" = "" ] ?PICKUPPARK)
    exten => _70[12345],n,NoOP(Transferred call, sending back to: ${BLINDTRANSFER:4:${extLeng}} )
    exten => _70[12345],n,dial(local/${BLINDTRANSFER:4:${extLeng}}@from-internal,,tr)
    exten => _70[12345],n,Hangup()
    exten => _70[12345],n(PICKUPPARK),NoOP(This is an inside call, Pick up Park Extension: ${EXTEN})
    exten => _70[12345],n(PICKUPPARK),ParkedCall(${EXTEN},parkinglot_lot2)
    exten => _70[12345],n(PICKUPPARK),Hangup()
    ;Park The call
    exten => _70[12345],n(PARK),Set(CHANNEL(parkinglot)=parkinglot_lot2)
    exten => _70[12345],n(PARK),Set(_PARKINGLOT=parkinglot_lot2)
    exten => _70[12345],n(PARK),Park(,from-internal,${BLINDTRANSFER:4:${extLeng}},,s)
    exten => _70[12345],n(PARK),Hangup()
    ;This is for park retrieval
    exten => _**70[12345],1,NoOP(PICK UP PARKED CALL!!!!!!!!!: ${EXTEN})
    exten => _**70[12345],n,ParkedCall(${EXTEN:2},parkinglot_lot2)
    
    and optionally, if you are using FreePBX 2.8...

    Code:
    [park-dial]
    include => park-dial-custom
    exten => t,1,Noop(Parked Call Timed Out and Got Orphaned)
    exten => t,n,Goto(ivr-3,s,1)
    exten => _[0-9a-zA-Z*#].,1,Noop(Parked Call Timed Out and Got Orphaned)
    exten => _[0-9a-zA-Z*#].,n,Goto(ivr-3,s,1)
    

    That last section is something I stole from the FreePBX generated code. You will probably want to edit this very last section of the code if you choose to use it (you don't have to!). It most likely will not work the way you want it to. It is normally found in extensions_additional.conf, but I now have it tacked to the end of extensions_custom.conf. You can enable call parking in FreePBX, set the desired behavior for orphaned calls, and then go search for [park-dial] in extensions_additional.conf. After you find it, cut and paste it to the end of extensions_custom.conf, and disable call parking in FreePBX.
    Last edited by nicknomo, May 16, 2014
    sorvani likes this.
  5. lgaetz Pundit

    There has been recent discussion on the FreePBX forum about a bug that prevents calls from being recorded once they are received from the parking log. Does your method also suffer from this problem?
  6. nicknomo Happy-IT-Guy


    I don't use call recording, so I couldn't tell you. I am currently seeing one bug, where I have trouble using the feature codes on the second parking lot... but that is about it.

    edit: I fixed this bug, I forgot to add this into the second parking lot.
    Code:
    parkedcalltransfers = caller                     
    parkedcallreparking = caller 
    
    The FreePBX generated code uses the default context, which simply calls Park(). I'd have to imagine if you are having call recording bugs on FreePBX, this probably wouldn't behave much differently.
    Last edited by nicknomo, Mar 14, 2014
  7. tm1000 Schmoozecom INC/FreePBX

    I need to clarify a few things for anyone who wants to attempt to use this code.

    The original FreePBX code you are basing your assumptions on is from FreePBX 2.8, in 2.11 parking was significantly refactored so I am not 100% sure your dialplan will even work and in Asterisk 12 it's no longer in features.conf. Multiple parking lots are avalible in park pro in 2.11 through the GUI otherwise there are/were many feature improvements added in 2.11 and parking into slots is on the list for 12.

    This is what happens when you stay on a release that is almost 4-5 years ago at this point.

    Other than that, nice job on figuring it all out. Very impressive work indeed! Thats what asterisk is all about building your own custom installation.

  8. nicknomo Happy-IT-Guy


    Well, the parking in FreePBX is turned off, so this is all just manually entered asterisk dialplan. I'm on Asterisk 11.5, so it all seems to be compliant in that respect. I was not aware that parking was changed a lot after 2.8 . The parking dialplan in 2.8 appears to me to be mostly just reliant on the asterisk default park application. I didn't see anything get set other than the park hints and the parking lot position. I'm guessing that this changed, or they made an elaborate dialplan instead?

    I will have to upgrade my FreePBX version and test it out. I have a virtual machine set up for testing, so I can just roll it back when I'm done. If it requires modifications, I will see if I can find and hopefully publish them.

    For asterisk 12, you are right, it doesn't use features.conf for parking lots. Instead it uses res-Parking.conf, but the syntax looks the same...
  9. nicknomo Happy-IT-Guy


    Tested with 2.11, and the code seemed to be working normally. Since the later versions of FreePBX apparently have no way of turning off the default lot configuration like in 2.8 (why???), I changed my multiple lot configuration to just be two completely separate lots. It appears to work the same, and should completely bypass any FreePBX generated dialplan.
    wardmundy likes this.
  10. sorvani New Member

    Love this alternate to the built in parking lot. When converting users who have had a key system for 15 years the built in parking was not working well.
    They were very attached to parking people on specific parking slots and this lets me do it. Made my customer very happy.

    Only problem I have with it now is that the FOP2 panel is not showing the parked calls. I posted something on their forums today so hopefully I'll find a solution.
    wardmundy likes this.
  11. nicknomo Happy-IT-Guy


    Hey, glad this was useful to someone. In regards to FOP2, I believe it relies on the FreePBX configuration data. If you configure the same settings in the FreePBX menu, it should show up in the FOP2 GUI, but I'm unsure what effects this might otherwise have. In theory, the code I've supplied should override the settings supplied by FreePBX, but I have not tested that. It should work with the 1 parking lot example, using the default parkedcalls context, but not with the two parking lot example. If you try that, and it works, let me know...

    Edit: I also made a small change to the code:
    I'm using:
    Park(,from-internal,${BLINDTRANSFER:4:${extLeng}},,s)

    instead of:
    Park(,,,,s)
    I was having trouble where follow me calls from a virtual extension weren't working right, so this code seemed to clear that up.
    Last edited by nicknomo, May 27, 2014
  12. tm1000 Schmoozecom INC/FreePBX

    Why? Because if you don't want Parking from FreePBX uninstall the module. Why would you disable the parking lot? It does the same thing as uninstalling the module, so just uninstall the module.
  13. tm1000 Schmoozecom INC/FreePBX

    FOP2 reads the FreePBX database of Parking Lots. If you are using this code then you aren't using FreePBX and FOP won't work for parking lots.

  14. nicknomo Happy-IT-Guy


    I didn't think about that... but the code was already there in convenient checkbox form to enable/disable. It just seems like a strange choice to take that out.
  15. tm1000 Schmoozecom INC/FreePBX

    Parking was rewritten from the ground up along with the fact that no other module has a "disable" ability (Exception Find me/Follow me) it was taken out. We are talking about making FreePBX have a more consistent user experience. If users don't want the features then remove the module. Checking the "disable" box in previous versions of FreePBX still required retrieve conf to ask parking what the dialplan is, regardless of if the box was checked or not (it was up to parking to return the dialplan or not) so in terms of removing the module there is actually less overhead. A win-win in the sense of usability and removal of "bloat"
  16. sorvani New Member

    Any idea how to get custom MoH do play when using this? instead of the default? The only complaint I have from one client is that they want the MoH to be different for the three parking lots, because they are being used for 3 different branch offices.

Share This Page