Paw Patrol Dialplan: dialing 1 goes to extension instead of next node

Hi Everyone!

I’m turning a Linksys PAP2 into a toy for my toddler. I have it mostly working, but there’s an error in my understanding with dialplans and WaitExtern.

I’m trying to have:

Answer and play intro music
while true
    Wait for a button press
    if pressed 1: play chase.wav
    else if pressed 2: play rocky.wav
    else if pressed 3: play marshall.wav
    else if pressed 4: play rubble.wav
    else if pressed 5: play zuma.wav
    else if pressed 6: play sky.wav

My dial plan is:

[from-internal]                
exten => 1,1,Answer()          
exten => 1,2,Playback(intro)   
exten => 1,3,Goto(s,1)         
                               
exten => s,1,WaitExten(60)     
                               
exten => 1,1,Playback(chase)   
exten => 1,2,Goto(s,1)         
                               
exten => 2,1,Playback(rocky)   
exten => 2,2,Goto(s,1)         
                               
exten => 3,1,Playback(marshall)
exten => 3,2,Goto(s,1)         
                               
exten => 4,1,Playback(rubble)  
exten => 4,2,Goto(s,1)         
                               
exten => 5,1,Playback(zuma)    
exten => 5,2,Goto(s,1)         
                               
exten => 6,1,Playback(sky)     
exten => 6,2,Goto(s,1)         
                               
exten => 7,1,Goto(s,1)         
exten => 8,1,Goto(s,1)         
exten => 9,1,Goto(s,1)         
exten => 0,1,Goto(s,1)         
exten => #,1,Goto(s,1)         
exten => *,1,Goto(s,1)         

When I press 1, the intro plays. I thought that after WaitExten(60), the following exten => 1,1,Playback(chase) would execute.

Loggs from pressing 1, then 2, then 3:

Running as user 'asterisk'
Running under group 'asterisk'
Connected to Asterisk 21.0.1 currently running on asterisk (pid = 18919)
    -- Executing [1@from-internal:1] Answer("PJSIP/6001-00000000", "") in new stack
    -- Executing [1@from-internal:2] Playback("PJSIP/6001-00000000", "intro") in new stack
    -- <PJSIP/6001-00000000> Playing 'intro.slin' (language 'en')
    -- Executing [1@from-internal:3] Goto("PJSIP/6001-00000000", "s,1") in new stack
    -- Goto (from-internal,s,1)
    -- Executing [s@from-internal:1] WaitExten("PJSIP/6001-00000000", "60") in new stack
    -- Executing [1@from-internal:1] Answer("PJSIP/6001-00000000", "") in new stack
    -- Executing [1@from-internal:2] Playback("PJSIP/6001-00000000", "intro") in new stack
    -- <PJSIP/6001-00000000> Playing 'intro.slin' (language 'en')
    -- Executing [1@from-internal:3] Goto("PJSIP/6001-00000000", "s,1") in new stack
    -- Goto (from-internal,s,1)
    -- Executing [s@from-internal:1] WaitExten("PJSIP/6001-00000000", "60") in new stack
    -- Executing [2@from-internal:1] Playback("PJSIP/6001-00000000", "rocky") in new stack
    -- <PJSIP/6001-00000000> Playing 'rocky.slin' (language 'en')
    -- Executing [2@from-internal:2] Goto("PJSIP/6001-00000000", "s,1") in new stack
    -- Goto (from-internal,s,1)
    -- Executing [s@from-internal:1] WaitExten("PJSIP/6001-00000000", "60") in new stack
    -- Executing [3@from-internal:1] Playback("PJSIP/6001-00000000", "marshall") in new stack

After hearing intro.wav, how can I have 1 play chase.wav?

Thanks for your help
Derek

You can’t have two extension 1s in the same context. You will need to goto a new context before using WaitExten.

I think given the application this should work:

[from-internal]
exten => _X!,1,Answer()
same => n,Goto(paw-patrol,s)

exten => i,1,Goto(1,1)

[paw-patrol]                       
exten => s,1,Playback(intro)           
same => n,WaitExten(60)

exten => i,1,Goto(s,2)     
                               
exten => 1,1,Playback(chase)   
same => n,Goto(s,2)         
                               
exten => 2,1,Playback(rocky)   
same => n,Goto(s,2)         
                               
exten => 3,1,Playback(marshall)
same => n,Goto(s,2)         
                               
exten => 4,1,Playback(rubble)  
same => n,Goto(s,2)         
                               
exten => 5,1,Playback(zuma)    
same => n,Goto(s,2)         
                               
exten => 6,1,Playback(sky)     
same => n,Goto(s,2)   

This changes the [from-internal] context to attempt to switch to the [paw-patrol] context if you dial anything; any digit 0 - 9 and matches on the first valid digit. If your ATA is set up correctly this will auto-dial when you press a digit or will auto-dial on off-hook. The i extension is the invalid handler, what Asterisk does if it can’t find that extension. In this case we force it.

This also uses the “shortcut” for doing extensions.

The [paw-patrol] extension is mostly the same except we start with the intro then go in to waitexten. Numbered extensions play the file and goto the second line of s, which is WaitExten. Invalid extensions also just go to WaitExten; assuming the intention is if the kid doesn’t press 1 - 6 we wait another minute and let him try again.

Goto addresses can be truncated on the left, not on the right. You need to specify the priority.

I used to know that before they locked our Asterisk behind a walled-garden of proprietary vendor.

Awesome! Thanks @david551 and @dewdude! I got things working the way I like.

A demo of what I did is https://www.youtube.com/watch?v=TPnLgXA_lZ4, and the source is GitHub - djshaw/toddlers-first-asterisk: A simple asterisk configuration with single digit dialplans for a toddler to learn how to use an analogue phone.

And just an oddity I noticed. If the dial plan is:

[from-internal]
exten => _X!,1,Answer()
 same => n,Background(intro)
 same => n,Goto(paw--patrol,s,1)

[paw-patrol]
...

If the user presses a button while the intro file is being played, then asterisk complains that the extension doesn’t exist. I naively expected to be in the paw-patrol context. Instead, I think Background() keeps the user from leaving the from-internal context, even though the Goto() step has been executed. This was the source of my original confusion. It feels like a bug to me, but I don’t have enough background on asterisk to know if there’s a reason for the behaviour.

No. Background means it listens for DTMF while playing the file, as opposed to playback.

You modified what I sent. The reason I wrote what I did was to prevent what you’re describing. It doesn’t work because you made it not work.

Background is effectively play the file looking for DTMF, and if DTMF is found, terminate the playback, put the DTMF back on the input queue, and run WaitExten, so the implied WaitExten gets run in the original context, before the Goto is executed, and, as WaitExten really does a dialplan restart, the dialplan progression, through the Goto, has been abandoned.

(I can’t remember if it actually pushes the digit back.)

I was on my phone earlier so a longer response explaining what’s going on wasn’t possible. But now that I’m here, let me try to explain what’s going on.

[from-internal]
exten => _X!,1,Answer()
 same => n,Background(intro)
 same => n,Goto(paw--patrol,s,1)

vs. (based on corrections I should have seen because I couldn’t test)

[from-internal]
exten => _X!,1,Answer()
same => n,Goto(paw-patrol,s,1)

exten => i,1,Goto(1,1)

I may have messed something up because…in theory, if you’re pressing a digit during background it should have just repeated the intro, although it returns to Answer…which may be an issue. You also forgot the invalid extension handler. You also had a typo in your Goto context. (In the absence of numbered steps or labels just count manually.) I do not know how your phone on the ATA is initiating a call. Your ATA has to dial something in to the PBX to start a call. Even in setups where it’s “pick up the handset and dial”, behind the scenes there’s dialplan that detects the off-hook and automatically transfers. Some ATAs will automatically dial an extension. The point is…your ATA’s endpoint exists in the from-internal context to determine dial-rules. My attempt was to make it so whatever your kid hit would match. Since I’m missing a very critical part of what you’re doing, the physical interface side, I can only guess.

But the basic point is we should basically answer the call, then GTFO out of that context. You’re essentially building an IVR, so ideally the entire IVR should exist in it’s own context. Even if you’re literally doing one phone, it makes things easier to understand.

Think of it like this way, dialplan contexts are like rooms. When you initiate a dial from a phone…your phone looks around it’s room to see if any of the doors matched what was typed. Sometimes the door can go to another phone/endpoint, like you dial 6657 and annoy your buddy Fred down in sales. Sometimes it takes you another room where you have more options. But every time your device/call changes room/context; the rules change.

In the context of an analog phone on an ATA, things can get confusing. For example, I have an ATA on my PBX setup to automatically dial on a match since it supports the protocol. So you can pick this phone up and dial a normal 10/11 digits and it will behave exactly like an analog phone, no having to send # to actually make the PBX send the call. But you can also set the ATA up to automatically dial an extension when it’s picked up, similar to a lobby or courtesy phone.

But the idea should be you somehow go from your phone’s starting context, then jump to paw-patrol context for everything, including the intro. There are other crazy tricks you could do as well that are a bit more advanced in the dialplan.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.