Creating a DIALPLAN for Tuning DVSwitch

; After fudging a AP command in rpt.conf
; 97 = autopatchup,context=dvs-set,dialtime=90000,farenddisconnect=1,noct,quiet=1

; Use Format: (AP command prefix) + (dvs mode 1-5) + (dvs tg)
; Requires that you set dvs mode each time with the leading digit 1-5.
; So, a command here of *97 1 3100 would set dmr 3100
; 2xxxx tunes dstar adhoc number only
; 2*1 tunes dstar REFxxx
; 2*2 tunes dstar DCSxxx
; 2*3 tunes dstar XLSxxx
; 2*4 tunes dstar XRFxxx
; 2*5 tunes dstar mem # or ## from file

; ** disconnects any mode

; The dialplan in extensions.conf

[dvs-set] ; this context needs to be unique in the system and match dialing context

exten = _1.,1,Wait,1 ; DMR
exten = _1.,2,NoOp() ; room for you to insert a command without renumbering anything
exten = _1.,3,SayAlpha(dmr,${EXTEN:1}) ; speak dmr tg before execution
exten = _1.,4,Wait,4 ; wait with time to cancel (autopatchdn)
exten = _1.,5,System(/opt/MMDVM_Bridge/ mode DMR) ; set mode
exten = _1.,6,Wait,1 ; allow some time to return from the shell
exten = _1.,7,System(/opt/MMDVM_Bridge/ tune ${EXTEN:1}) ; set TG
exten = _1.,8,Hangup ; done/hangup

exten = _2x.,1,Wait,1 ;The following for dstar adhoc
exten = _2x.,2,NoOp()
exten = _2x.,3,SayAlpha(d*,${EXTEN:1}) ; speak dstar & tg before execution
exten = _2x.,4,Wait,4
exten = _2x.,5,System(/opt/MMDVM_Bridge/ mode DSTAR)
exten = _2x.,6,Wait,1
exten = _2x.,7,System(/opt/MMDVM_Bridge/ tune ${EXTEN:1})
exten = _2x.,8,Hangup

exten = _2*1.,1,Wait,1 ;The following for dstar-REF
exten = _2*1.,2,NoOp()
exten = _2*1.,3,SayAlpha(d*,ref${EXTEN:2}) ; speak dstar ref & tg before execution
exten = _2*1.,4,Wait,4
exten = _2*1.,5,System(/opt/MMDVM_Bridge/ mode DSTAR)
exten = _2*1.,6,Wait,1
exten = _2*1.,7,System(/opt/MMDVM_Bridge/ tune ref${EXTEN:2})
exten = _2*1.,8,Hangup

exten = _2*2.,1,Wait,1 ;The following for dstar-DCS
exten = _2*2.,2,NoOp()
exten = _2*2.,3,SayAlpha(d*,dcs${EXTEN:2}) ; speak dstar dcs & tg before execution
exten = _2*2.,4,Wait,4
exten = _2*2.,5,System(/opt/MMDVM_Bridge/ mode DSTAR)
exten = _2*2.,6,Wait,1
exten = _2*2.,7,System(/opt/MMDVM_Bridge/ tune dcs${EXTEN:2})
exten = _2*2.,8,Hangup

exten = _2*3.,1,Wait,1 ;The following for dstar-XLS
exten = _2*3.,2,NoOp()
exten = _2*3.,3,SayAlpha(d*,xlx${EXTEN:2}) ; speak dstar xls & tg before execution
exten = _2*3.,4,Wait,4
exten = _2*3.,5,System(/opt/MMDVM_Bridge/ mode DSTAR)
exten = _2*3.,6,Wait,1
exten = _2*3.,7,System(/opt/MMDVM_Bridge/ tune xls${EXTEN:2})
exten = _2*3.,8,Hangup

exten = _2*4.,1,Wait,1 ;The following for dstar-XRF
exten = _2*4.,2,NoOp()
exten = _2*4.,3,SayAlpha(d*,xrf${EXTEN:2}) ; speak dstar xrf & tg before execution
exten = _2*4.,4,Wait,4
exten = _2*4.,5,System(/opt/MMDVM_Bridge/ mode DSTAR)
exten = _2*4.,6,Wait,1
exten = _2*4.,7,System(/opt/MMDVM_Bridge/ tune xrf${EXTEN:2})
exten = _2*4.,8,Hangup

exten = _2*5.,1,Wait,1 ;The following for dstar memory file /opt/mmdvm/dstar.mem
exten = _2*5.,2,NoOp()
exten = _2*5.,3,SayAlpha(d*,m${EXTEN:3}), ; speak dstar & mem# before execution
exten = _2*5.,4,Wait,3
exten = _2*5.,5,System(/opt/MMDVM_Bridge/ mode DSTAR)
exten = _2*5.,6,Wait,1
exten = _2*5.,7,System(/opt/MMDVM_Bridge/ ${EXTEN:3}) ; calls a secondary shell that hands off info to dvs tune
exten = _2*5.,8,Hangup

exten = _3.,1,Wait,1 ; YSF
exten = _3.,2,NoOp()
exten = _3.,3,SayAlpha(ysf,${EXTEN:1}) ; speak YSF & tg before execution
exten = _3.,4,Wait,4
exten = _3.,5,System(/opt/MMDVM_Bridge/ mode YSF)
exten = _3.,6,Wait,1
exten = _3.,7,System(/opt/MMDVM_Bridge/ tune ${EXTEN:1})
exten = _3.,8,Hangup

exten = _4.,1,Wait,1 ; P25
exten = _4.,2,NoOp()
exten = _4.,3,SayAlpha(p25,${EXTEN:1}) ; speak p25 & tg before execution
exten = _4.,4,Wait,4
exten = _4.,5,System(/opt/MMDVM_Bridge/ mode P25)
exten = _4.,6,Wait,1
exten = _4.,7,System(/opt/MMDVM_Bridge/ tune ${EXTEN:1})
exten = _4.,8,Hangup

exten = _5.,1,Wait,1 ; NXDN
exten = _5.,2,NoOp()
exten = _5.,3,SayAlpha(nxdn,${EXTEN:1}) ; speak nxdn & tg before execution
exten = _5.,4,Wait,4
exten = _5.,5,System(/opt/MMDVM_Bridge/ mode NXDN)
exten = _5.,6,Wait,1
exten = _5.,7,System(/opt/MMDVM_Bridge/ tune ${EXTEN:1})
exten = _5.,8,Hangup

exten = _**.,1,Wait,1 ; disconnect seq
exten = _**.,2,NoOp()
exten = _**.,3,SayAlpha(disc)
exten = _**.,4,Wait,3
exten = _**.,5,,System(/opt/MMDVM_Bridge/ tune disconnect) ; set TG dis
exten = _**.,6,Hangup

;===DStar Memory File===
; The intention here was just a method to connect systems that can not be entered into a 15 usable dtmf digit string reasonably. But you could just store your favorite 10 for ease of dialing.
;To use dstar memory calls, you need to create a file in /opt/MMDVM_Bridge/dstar.mem
;and populate it one dstar connection of any valid call that can be made through DVS per line
;Do not put anything else in the file as it begins reading from line 1 (no comments or blank lines)
;A extra command in the dialplan of ” 2*5 xx ” will call the line# of the memory file.

;Requires one additional batch file in the /opt/mmdvm_bridge/ directory called with these contents


;/opt/MMDVM_Bridge/ tune $(sed “$1q;d” /opt/MMDVM_Bridge/dstar.mem)

;(for some reason I could not execute this inside the dialplan and suspect it’s our older version of asterisk or some bad sytax… so, using alt method)

;Don’t forget to set ownership and permissions of the .sh file

;While this is not a perfect model of operation, it is a functional example for which allows you to develop your own methods beyond it using methods and principles you see.

;The intention here was the old KISS rule and to keep it all in one place as much as possible for easy understanding. Obviously, this will challenge your memory if you do not use it often.

;For those of you who require such functionality, make a cheat sheet to carry with you mobile/portable etc.

; To keep my extensions.conf file a bit cleaner, I set this in a file in /etc/asterisk/custom named dvs.conf and call it at the end of extensions.conf
; #includeifexists custom/dvs.conf

Passing DTMF to Shell Scripts

Setting Up



So, somewhere in our dialplan, we need to create the context ‘pass2script’ and this is done in extentions.conf


[pass2script] ; this context needs to be unique in the system

exten = _X.,1,Wait,1

exten = _X.,n,SayAlpha(/var/lib/asterisk/sounds/activated,${EXTEN}) ; allison says something and then speaks the dtmf string {EXTEN}

exten = _X.,n,Wait,3 ; pause for a chance to cancel by hitting DTMF # (hangup)

exten = _X.,n,System(/source/of/ ${EXTEN}) ; here we pass the dtmf string to shell

exten = _X.,n,Hangup


So, *97 12345 in our example here, would pass 12345 to the shell for *97 is our executing command.

Outside of the ‘autopatch’ we used to capture and pass the dtmf, this dialplan is pure asterisk and you can use all asterisk dialplan functions for evaluating, reformatting and executing.

You will need your shell script to receive the ‘dtmf number string’ accordingly and help for that is available on the web as ‘passing variables to shell scripts’.

The skinny is that you would use the string inside your shell as “$1” since we have only one ‘argument string’ to pass for evaluation at a time.

You can evaluate and pass to internal asterisk/app_rpt functions as well, just using the dialplan.

Additionally evaluate that string inside your dialplan and send to different shell scripts.

Search www asterisk help for that. Inside the dialplan, the DTMF string is simply {EXTEN}

If you like to create your own functionality, you will find this tool/workaround essential for wide flexible control.

It has been well tested method since 2012, so if you are having any issues, check all your syntax.

You could have multiple autopatch dtmf hand-off’s as long as you first provide a new unique command number for it and a new unique context for it in your dialplan.

Practical uses can be site or home control via usb or network relays, radio control/ digital mode control functions, web execution scripts etc, all dependent on your script/dialplan.

So you can see that your imagination is your limit. Go for it.

System Time Set using Radio DTMF

A means to set system clock with DTMF RADIO COMMANDS.

First I want to point out several things.
Read the warnings at the bottom.
This is not a perfect thing, but a framework to meet a end need.
You will likely need to make adjustments to it for your particular circumstance(s).

It was intended for Acid users who have no internet connection on their system but can be adapted to fit many situations.
While there are more than a dozen ways to do the same thing,
I chose this one to show to the group for the simplicity of implementation to those that are not as linux savvy, but have learned asterisk somewhat.

If you are in the US and have had the same system running for many years without updating the zoneinfo files, you should do that and copy the new timezone file to your /etc/localtime because the Daylight Savings Time that changed a few years ago (again) has probably been giving you some frustration on the time change twice or four times a year.  More info on that on the web:

SO, I am implementing this from the phone patch. Using the default dial to open the patch.

By default, (*6) +A+ HHMM is all the dtmf you would need to enter the time in 24hr format. Example *6A1345 will set the clock to 1:45pm

I chose ‘A’ as the dialing catch since it’s unlikely to be in your normal phone extensions and is intended for ‘no internet service’ installs set by RADIO.

If there are not 4 numbers to follow the “A”, it will fall through, otherwise it will say ‘the-time-is’, the four numbers you are setting, then pause for 10 seconds to allow you to hang-up ( *0 ) if you wish to cancel before it sets time and reboots your machine.

If you are trying to sync it to the second, enter it 15 seconds before the top of a minute (a 20 sec head start). Because asterisk always runs with a match as soon as it appears. So that would start running on the last/4th dtmf time digit (5th digit entered) after the phone patch prefix, not when you unkey the radio.

In extensions.conf  just under [radio]

exten = _Axxxx,1,Goto(set_time_clock|${EXTEN:1}|1)   ;set time, send to subscript without leading digit

(place the rest at the end of extensions.conf file….)

[set_time_clock]; by kb8jnm
exten =_X.,1,Wait(5)
exten =_X.,2,Playback(rpt/thetimeis)
exten =_X.,3,SayAlpha(${EXTEN})       ; Read back Dialed Number for time
exten =_X.,4,Wait(10)                  ; allow 10 seconds to hang-up (*0 ) if not correct
exten =_X.,5,System(date +%T -s \”${EXTEN:0:2}:${EXTEN:2:2}:00\”) ;format ‘HH:MM:00’ – 24hr format
exten =_X.,6,System(reboot)
exten =_X.,7,Hangup

Adjusting the timeclock on a live system can have unknown affect on things that are running  & relying on timers.

What is not a problem now could be a problem latter depending on your cron and sched settings for what is currently active on the system.

If you have much a time slippage in your clock, adjust it more often or when it gets 2 minutes or so out of time.

So at a minimum, shutdown links before adjusting the clock. My remedy for this was a reboot after setting.
I am thinking of you folks that have unconnected mountain top systems you can’t get to if a problem arises.
So, To avoid many unexpected problems that can occur in system timers mis-match, the system will reboot right after setting the clock.

I suggest you leave ‘REBOOT’ in place unless you have good reason to take it out. But you have been warned.

If you like it… great… if you don’t like it… make it better and shove it out to the group for others to improve on.
Probably better to hand the extension data off to a shell script, shutdown asterisk, set-clock, restart asterisk & exit. But not if you use cron for all your app_rpt and system scheduling needs.
But this is simple and with the full reboot, resets ‘all’ system timers before ‘any’ can be a problem. Unless you change that.

Sync time with NTP for app_rpt

(internet connected systems only)

While this probably should be done by your OS, from cron

Here is a script to sync your time with NTP.

Give  it a name ( , Apply ownership

Give it a command in rpt.conf, Run that command  from the macro/sched late at night.

/usr/sbin/ntpdate > /etc/asterisk/log/timelog.txt

Will also create a log file if you need to check that it has been running correctly.
If not needed, delete all after and including ">"
Hopefully these are more of a example of how to do other things for those that are learning.

Macro Delay Execution Timer

This script was created to execute a  delay then a command.

Meaning that you issue a command as part of some other simple or complex function and have a delay before it executes a second part or a cancellation of the same.

It could have a multitude of applications once you understand what it is actually doing. But for our example here, it is a simple one.

Our example, we have a light that we use to light our way from the repeater site at night and often someone using it for access to or from the repeater site at night forgets to turn it off. So we need a auto-turn-off for this light-up function.


We are calling the script

If you are using this for many things or nodes, make each instance a unique name with node number and/or special function name.

Create a command for the script in rpt.conf

XXXX=cmd, etc/asterisk/myscripts/

Now our macro for calling the “turn light on” looks like this before we start:


55= *9987 *9988# ; (play file” light-on” and switch parallel port pin 5 on)

56= *9989 *9990# ; (play file “light-off” and switch par port pin 5 off)


55= *9987 *9988 *XXXX# ;insert your script command issued above

Edit the script and set the timer in seconds and call the macro that turns it off when the timer has expired.

Make the script 775 ownership.

DOWNLOAD as a file

# mike/kb8jnm –
# create delay / run command
# make a command for this script, call it from a macro string
# set wait time in seconds
sleep 1200
# execute command (calling a macro to shut off the called function)
# format is – rpt fun NODE# CMD#
asterisk -rx “rpt fun 29283 *556
# will clean exit after waiting and executing

# end of file EOF

This simple example is just to show functionality. Use your imagination to fit your need.  Be careful not to put it in a situation where it could be called multiple times in automation.

Barry, G8SAU Used it for this…

I have made a repeater mast head pre-amp control
that users can enable turn on with a DTMF code  eg *51 that gives a boost 
to the RX for a period of 30 mins then reverts to OFF

for those moments that need extra coverage on RX when Fixed user is working 
a Mobile user or an HT user on the edge of coverage, RX wise.

Script – Initial ID / Normal ID

Many of us that are use to the older premium  “hard-wire” style repeater controller are also use to having a initial ID that would allow for a separate ID to be played when the repeater was keyed for the first time from a sleep state.

Then afterwards, would play a normal ID at “id-interval” timing that would be a short ID for in-use.

Most of us would use that Initial ID to play a long ID stating extended info about the repeater like location information so when someone stumbled on the repeater late at night or when nobody was around to ask, they would have the correct info about which repeater they were accessing and where it was.

While there was limited ways to accurately obtain this info and act on it in a way that was uncomplicated for a control-op to install correctly and use, I took it to task.

This is totally a Bash Script that needs to be run from start-up
or from a command line (should do for testing beforehand).
Made/Tested with ACID.

Here is the result.

You need two audio files of the ID's before you start.
Here called "idmsg1" (initial/sleep id)
& "idmsg2" (wake/regular id) and 
our actual id message is "idmsg"
You can just take one of those files and copy ( cp ) it to a new filename for idmsg 
like this:  cp idmsg1.wav idmsg.wav
(assuming you are in the directory of the files)

I'll call the shell script
If running multi-nodes on a single server, you might want to make a new filename like:
so you can have separate id's for each nodes.
This would mean making a script for each node and running a new process for each.
If you do this, change the /tmp/init-id.txt located in "two places" in the
file to the same unique format.

In rpt.conf
You need to give it a command:ex

Use the startup macro to call it:ex

You need to edit before running:
Node number
files and locations of your 2 id files and the /location/name of your voice-id file
(idrecording =/etc/asterisk/msg/idmsg) in both locations in the script.
Pay close attention to spaces when editing as it will change things in error.

Make the files & script we are using 775 ownership

(from a shell)
cd /etc/asterisk/myscripts (where located)
./  ( ./ with actual name you use .sh)
and you use <ctrl> + C to break and stop it from command line running it.
change sleep number to 20 for command line testing and 200 when auto
loading to limit file accesses. 
I'm Assuming a 5 minute or better id interval.

Do pay close attention to spaces in the file when editing.
You will create errors if not and not understand where from.

Download as File

At the bottom of this page is shown what the response will look like from a command line.

When needed, the script simply 
copies idmsg1 to idmsg (sleep/init-id)
copies idmsg2 to idmsg (wake/normal-id)
But will not attempt to write while ID is playing. ider_state=0

# - mike/kb8jnm
# overwrite id files to create initial id & regular id
# based on app_rpt - "ider_state" variable.
# make ownership of this file 775
# -See sleep ### at the bottom is in seconds.
# Lower the value to 20 for testing live from a command line.
# You will see the updates faster.

# preset some parms

# this is a infinate loop
while :

# read our parms for node - put in text file - (edit node number)
 asterisk -rx "rpt xnode 29283" > /tmp/init-id-29283.txt

# parse our parms from that file and only rewrite id if it needs it
 while read line
 echo $line

 if [ "$line" = "$idsleep" ] && [ "$idis" = "wakeid" ]; then
# edit locations and names next line
 cp /etc/asterisk/msg/idmsg1.wav /etc/asterisk/msg/idmsg.wav
 echo " ** " $line $idsleep "-init ID"
 if [ "$line" = "$idwake" ] && [ "$idis" = "sleepid" ]; then
# edit locations and names next line
 cp /etc/asterisk/msg/idmsg2.wav /etc/asterisk/msg/idmsg.wav
 echo " ** " $line $idwake "-normal ID"
 done </tmp/init-id-29283.txt

# show status if running from a command line for test
echo "ID IS " $idis

# wait a bit to limit file access (in seconds)
sleep 200


If everything is working fine, 
you will see something like this at a command line
when you execute it:

RPT_NUMLINKS=1     ;these are parms returned by app_rpt on xnode

ider_state=2       ;when our script sees this line it acts.
 **  ider_state=2 ider_state=2 -init ID     ;these are echos of internal vars

ID IS  sleepid      ;this is a echo of internal var of current state.

Don't forget to check your timers...
totime=600000 ;in milisoconds 300000=5min
idtime=590000 ; in 10ms
politeid=500000 ; =8m20s
sleeptime=1830 ;in seconds 300=5m