Category: Asterisk

How to make FreePBX and other Asterisk-based systems send voicemails and notifications to two or more email addresses

FreePBX and Asterisk do not allow you to send voicemails and notifications to multiple email addresses. But, there is a way to do it. Here are the simple steps:

  1. From a Linux command prompt, open the file /etc/aliases in your favorite text editor. Add a line to the end of that file, using a descriptive name that should not duplicate any of the names already in this file, nor the username of any users on the system. The line should look like this (this is just an example, obviously):
    foo: user1@gmail.com,user2@gmail.com
    Where foo can be replaced with any alias name you like that does not duplicate an existing alias or username.  You can add as many email addresses as you need, but they should be separated only by commas, and NO spaces other than the one between the alias name and the first email address.
  2. From the Linux command prompt, run the command newaliases and make sure that no errors are reported (you should not see any output at all).
  3. If you are running raw Asterisk, then wherever you would normally use a single email address, you can now use the alias name @localhost, for example, foo@localhost.
  4. If you are using an old version of FreePBX then it may not allow you to use addresses ending in @localhost. In that case, from the Linux command prompt run the command hostname -f and then use the result of that in place of localhost in step 3.
  5. You can repeat these steps as needed to create additional aliases for different users on your system.  You might want to use meaningful alias names, for example mikevm to send Mike’s voicemails to multiple addresses.
  6. Don’t forget that if you are only sending voicemail notifications, and not the entire voicemail as an attachment, that many wireless companies have SMS gateway addresses that you can send an email to, that will convert the first 140 characters of the email to an SMS text message.  You can find a list of email address formats to use for this purpose in this article:  How To Send Email To Any Cell Phone (for Free)
  7. This technique is not limited to Asterisk and FreePBX; it should provide a solution for any software that can’t seem to deal with more than one email address at a time.

Why you can’t get SRTP encryption to work between Asterisk and your VoIP adapter or phone

Some recent versions of Asterisk (Asterisk 11 in particular) have built-in SRTP support of sorts. As Wikipedia notes,

The Secure Real-time Transport Protocol (or SRTP) defines a profile of RTP (Real-time Transport Protocol), intended to provide encryption, message authentication and integrity, and replay protection to the RTP data in both unicast and multicast applications. It was developed by a small team of IP protocol and cryptographic experts from Cisco and Ericsson including David Oran, David McGrew, Mark Baugher, Mats Naslund, Elisabetta Carrara, James Black, Karl Norman, and Rolf Blom. It was first published by the IETF in March 2004 as RFC 3711.

In simple terms, SRTP encrypts the audio of your VoIP calls, making it much more difficult for anyone with a packet sniffer to listen in.

Let’s say you have an Android-based tablet and you are running CSipSimple. If you have configured it as an extension off your Asterisk 11 server, and you turn SRTP on in the security settings, you will likely find that outgoing calls work fine but incoming calls do not.  The reason is that you need to add one line to the extension’s configuration settings in Asterisk:

encryption=yes

If you are using FreePBX then it’s only a bit more complicated.  You’d need to add two lines to the /etc/asterisk/sip_custom_post.conf file:

[####](+)
encryption=yes

Replacing #### with the extension number. Once you have done this and reloaded Asterisk, it will only communicate with the endpoint using SRTP.

BUT there is one problem here.  With some other VoIP devices and softphones, once your have enabled SRTP, any attempt to place an outgoing call will not work.  And, if you watch the Asterisk CLI, you may see lines similar to this:

[2013-12-19 08:18:57] NOTICE[2949][C-000005e9]: sip/sdp_crypto.c:255 sdp_crypto_process: Crypto life time unsupported: crypto:1 AES_CM_128_HMAC_SHA1_80 inline:6aV+PFYMnVJVUZuxug9EM5yefPnfOrNhHcKLSABE|2^20
[2013-12-19 08:18:57] NOTICE[2949][C-000005e9]: sip/sdp_crypto.c:265 sdp_crypto_process: SRTP crypto offer not acceptable
[2013-12-19 08:18:57] WARNING[2949][C-000005e9]: chan_sip.c:10454 process_sdp: Rejecting secure audio stream without encryption details: audio 17100 RTP/SAVP 0 8 18 104 101

The problem is that in Asterisk, “any SRTP offers that specify the optional lifetime key component will fail”, as is detailed in this submitted patch to Asterisk:

(ASTERISK-17899) [patch] Adds a ‘ignorecryptolifetime’ (Ignore Crypto Lifetime) option to sip.conf for SRTP keys specifying optional ‘lifetime’

If if the device or softphone had a setting to disable sending the lifetime parameter, it probably would work. If users would go through the trouble of applying this patch to Asterisk, it would probably work, but many users either don’t know how to do that, or they are running a pre-built distribution and don’t want to or cannot tamper with it (also, any upgrades to Asterisk thereafter would require re-application of the patch). If Digium would apply this patch to Asterisk and push it out in upgrade releases, it probably would work. But for whatever reason, though this patch was first posted back in May of 2011, Digium has not seen fit to roll it into Asterisk.

So, this may very well be the reason, or at least one of the reasons, why you can’t get SRTP encryption to work between Asterisk and your VoIP adapter or phone! Basically, your VoIP device or softphone and Asterisk just don’t want to play nice with each other.

We’ve heard that some other varieties of PBX software, such as FreeSWITCH, might not have this issue, but since we don’t have a working FreeSWITCH installation at the moment we cannot comment on that.

Link: Improving Asterisk call quality with SIP jitter buffers

I had a customer let me know that they had improved their call quality from WiFi and 3G connections by turning on the Asterisk jitter buffers for SIP connections. If you have any extensions where connection quality is intermittent it could be worth trying.

Full article here:
Improving Asterisk call quality with SIP jitter buffers (SysAdminMan Blog)

Note that the article mentions that “This can by done with the FreePBX SIP Settings module”, but does not mention the settings when using that method. Although they should be fairly obvious, we’ll mention them anyway:

Under Settings / Asterisk SIP Settings in the Jitter Buffer Settings section:
Jitter Buffer: Enabled
Force Jitter Buffer: No
Implementation: Adaptive
Jitter Buffer Logging: Disable
Jitter Buffer Size: 200 (jbmaxsize) 1000 (jbresyncthreshold)

The two items in bold text correspond to the ones discussed in the above-mentioned article.

How to hack the FreePBX blacklist for better call blocking capability

NOTE:  There is a newer version of this article that adds TrueCNAM scoring to help weed out telemarketers, robo-callers, and other “spam” callers.  See How to hack the FreePBX blacklist for better call blocking capability, take 2 – adding TrueCNAM scoring for that article, or continue here if you don’t want to use TrueCNAM scoring.

Have you ever wished that you could blacklist calls in FreePBX using criteria other than just the exact phone number?  It’s quite possible, and here’s an explanation of how it can be accomplished.

First, using a text editor such as nano, go into the file /etc/asterisk/extensions_additional.conf and find the context headed [app-blacklist-check]. It will probably look like this:

[app-blacklist-check]
include => app-blacklist-check-custom
exten => s,1(check),GotoIf($[“${BLACKLIST()}”=”1”]?blacklisted)
exten => s,n,Set(CALLED_BLACKLIST=1)
exten => s,n,Return()
exten => s,n(blacklisted),Answer
exten => s,n,Wait(1)
exten => s,n,Zapateller()
exten => s,n,Playback(ss-noservice)
exten => s,n,Hangup

Note that this is a pretty simple macro context. The first line checks to see if a caller ID number appears in the Asterisk blacklist, and if so, it shuffles the call off to a “number not in service” recording.

If you copy and paste this entire context into the file /etc/asterisk/extensions_override_freepbx.conf and remove the “include” line at the start of the macro, you can then modify it to do what you want. Let’s look at that same context again, but with a few added lines, as it might appear in /etc/asterisk/extensions_override_freepbx.conf

[app-blacklist-check]

;Make sure CDR DID field is set on blacklisted calls
exten => s,1(check),Set(CDR(did)=${FROM_DID})
;Original first line of context with line number changed
exten => s,n,GotoIf($[“${BLACKLIST()}”=”1”]?blacklisted)
;Blacklist Caller ID names found in custom Asterisk database blistname if used
exten => s,n,GotoIf($[“${DB_EXISTS(blistname/${TOUPPER(${CALLERID(name)})})}”=”1”]?blacklisted)
;Blacklist Caller ID names of single letter followed by 9 or more digits
exten => s,n,Set(regx=^[A-Z][0-9]{9}[0-9]* *$)
exten => s,n,GotoIf($[${REGEX(“${regx}” ${CALLERID(name)})} = 1]?blacklisted)
;Blacklist numbers where first digit of 7 digit local number is 0 or 1
exten => s,n,Set(regx=^[+]?1?[0-9]{3}[01][0-9]{6}$)
exten => s,n,GotoIf($[${REGEX(“${regx}” ${CALLERID(num)})} = 1]?blacklisted)
;Blacklist numbers where first digit of area code is 0 or 1
exten => s,n,Set(regx=^[+]?1?[01][0-9]{9}$)
exten => s,n,GotoIf($[${REGEX(“${regx}” ${CALLERID(num)})} = 1]?blacklisted)
;Blacklist numbers where first three digits of 7 digit local number are 555
exten => s,n,Set(regx=^[+]?1?[0-9]{3}555[0-9]{4}$)
exten => s,n,GotoIf($[${REGEX(“${regx}” ${CALLERID(num)})} = 1]?blacklisted)
;Blacklist numbers that start with 1 but are longer than 11 digits total
exten => s,n,Set(regx=^[+]?1[0-9]{11}[0-9]*$)
exten => s,n,GotoIf($[${REGEX(“${regx}” ${CALLERID(num)})} = 1]?blacklisted)
;Blacklist numbers of less than 7 digits in length
exten => s,n,GotoIf($[${LEN(${CALLERID(num)})} < 7]?blacklisted)
;Blacklist numbers of 8 digits in length
exten => s,n,GotoIf($[${LEN(${CALLERID(num)})} = 8]?blacklisted)
;Next line is from the original blacklist context
exten => s,n,Set(CALLED_BLACKLIST=1)
;Special CallerID name lookup; should not really be here but works
exten => s,n,ExecIf($[“${DB_EXISTS(cidname/${CALLERID(num)})}”!=”1″]?Return())
exten => s,n,Set(CALLERID(name)=${DB(cidname/${CALLERID(num)})})
exten => s,n,Set(__SKIPCIDLOOKUP=1)
;More original blacklist context
exten => s,n,Return()
exten => s,n(blacklisted),Answer
;Prepend *BL* to Caller ID name of blacklisted numbers so they can be distinguished in CDR
exten => s,n,Set(CALLERID(name)=*BL*${CALLERID(name)})
;Set Call Detail Record Userfield to Blacklisted
exten => s,n,Set(CDR(userfield)=Blacklisted)
;Still more original blacklist context
exten => s,n,Wait(1)
exten => s,n,Zapateller()
exten => s,n,Playback(ss-noservice)
exten => s,n,Hangup

;–== end of [app-blacklist-check] ==–;

The lines in blue are from the original context that was copied from /etc/asterisk/extensions_additional.conf.  We should mention here that not all the ideas in the new lines are original with us; some are adaptations of things we’ve read over many months in various forums.

You don’t need to use all of these added lines shown.  On the other hand, you can add your own customizations.  Here is what each added line (or set of lines) means:

The change to line 1 (moving the original line 1 down to the next line) adds Set(CDR(did)=${FROM_DID}), which causes the call detail record to show the DID the call came in on for blacklisted calls.

;Blacklist Caller ID names found in custom Asterisk database blistname if used
exten => s,n,GotoIf($[“${DB_EXISTS(blistname/${TOUPPER(${CALLERID(name)})})}”=”1”]?blacklisted)

This addition allows you to blacklist by exact Caller ID name.  To add a name to the blacklist-by-name database, go into the Asterisk CLI and enter this:

database put blistname NAME 1

Where NAME is the name you want to add – enclose it in quotation marks if it contains spaces:

database put blistname “SOME NAME” 1

You can use a descriptive word if you like in place of the number 1 at the end of the line.  To delete an already entered name:

database del blistname NAME

And to see what’s already in the blacklist-by-name database:

database show blistname

Next we come to:

;Blacklist Caller ID names of single letter followed by 9 or more digits
exten => s,n,Set(regx=^[A-Z][0-9]{9}[0-9]* *$)
exten => s,n,GotoIf($[${REGEX(“${regx}” ${CALLERID(name)})} = 1]?blacklisted)

These lines are an example of blacklisting a Caller ID name using a regular expression. This will catch any Caller ID name that starts with a single letter and is followed by 9 or more digits, and any number of spaces at the end.  This particular example will get rid of those irritating Vnnnnnnnnn… name calls, even if they change the starting letter to something other than “V”.

;Blacklist numbers where first digit of 7 digit local number is 0 or 1
exten => s,n,Set(regx=^[+]?1?[0-9]{3}[01][0-9]{6}$)
exten => s,n,GotoIf($[${REGEX(“${regx}” ${CALLERID(num)})} = 1]?blacklisted)

;Blacklist numbers where first digit of area code is 0 or 1
exten => s,n,Set(regx=^[+]?1?[01][0-9]{9}$)
exten => s,n,GotoIf($[${REGEX(“${regx}” ${CALLERID(num)})} = 1]?blacklisted)

;Blacklist numbers where first three digits of 7 digit local number are 555
exten => s,n,Set(regx=^[+]?1?[0-9]{3}555[0-9]{4}$)
exten => s,n,GotoIf($[${REGEX(“${regx}” ${CALLERID(num)})} = 1]?blacklisted)

These are three examples of blacklisting numbers by regular expression patterns.  The first example blacklists numbers that have an invalid exchange (where the 7-digit part of the number starts with 0 or 1), while the second blacklists numbers that come in with an area code starting with 0 or 1, which is invalid.  The third blocks numbers that appear to come from the “directory assistance” exchange 555 in any area code. In all cases, it does not matter if the number starts with a leading + and/or 1.  Note that Asterisk has a fairly restrictive syntax for regular expressions, so you can’t do many of the substitutions that would be possible in other computer languages. See the article, Did you know that Asterisk has the ability to evaluate Regular Expressions, though not in the same way as Perl or FreeSWITCH? for more information.

You can always add additional blacklist patterns by duplicating an appropriate pair of lines (for blacklisting by name or number pattern) and then modifying the regular expression.  For example, to block calls from certain specific area codes, you could use a regular expression of the form ^[+]?1?(xxx|yyy|zzz)[0-9]{7}$ where xxx, yyy, and zzz are the area codes you want to block.  You can include as many area codes as you need, separated by the | character.

;Blacklist numbers of 8 digits in length
exten => s,n,GotoIf($[${LEN(${CALLERID(num)})} = 8]?blacklisted)

This is an example of blocking numbers of a specific length.  If you have a bad caller that sends numbers that are exactly 8 characters in length, this will catch them. You can, of course, change the “8” to catch other bad length numbers, but be careful not to inadvertently block wanted international or other valid calls with non-standard number lengths.

The next added section consists of these lines:

;Special CallerID name lookup; should not really be here but works
exten => s,n,ExecIf($[“${DB_EXISTS(cidname/${CALLERID(num)})}”!=”1″]?Return())
exten => s,n,Set(CALLERID(name)=${DB(cidname/${CALLERID(num)})})
exten => s,n,Set(__SKIPCIDLOOKUP=1)

It could be argued that this doesn’t really belong in the blacklist code, so feel free to omit it if you don’t like it – remember, these are just examples.  What this does is checks the Asterisk Phonebook to see if the calling number appears there, and if it does, it sets the Caller ID name to the name associated with that number in the Phonebook.  There are other ways to do this, but we show it here for one simple reason – you could use it to “whitelist” a certain number that would otherwise be taken out by a regular expression-based rule, although you’d have to modify the dialplan shown here a bit to do so.  As it stands, this only does the Asterisk Phonebook lookup, and applies the name from the Asterisk Phonebook if it finds it there.

There is one issue with doing this, and that is that if you use another Caller ID lookup source it will override the Asterisk Phonebook lookup.  To avoid that, you can copy the [cidlookup] context from /etc/asterisk/extensions_additional.conf to /etc/asterisk/extensions_override_freepbx.conf and change the first line to a test for the SKIPCIDLOOKUP variable.  For example, if the first line is:

exten => cidlookup_1,1,Set(CURLOPT(httptimeout)=7)

You could change it to:

exten => cidlookup_1,1,ExecIf($[“${SKIPCIDLOOKUP}”=”1”]?Return())
exten => cidlookup_1,n,Set(CURLOPT(httptimeout)=7)

Don’t forget to change the line number 1 to n in the original first line, since it’s no longer line 1.

Finally, the last hack shown is this – you would probably want to use one or the other of these, but not both:

;Prepend *BL* to Caller ID name of blacklisted numbers so they can be distinguished in CDR
exten => s,n,Set(CALLERID(name)=*BL*${CALLERID(name)})

;Set Call Detail Record Userfield to Blacklisted
exten => s,n,Set(CDR(userfield)=Blacklisted)

We don’t recall where we first saw this, but it is a great idea.  In the first example, if the call is blacklisted, the characters *BL* are added to the start of the Caller ID name, and appear that way in the call detail. In the second example, the “Userfield” in the call detail record is set to the word “Blacklisted”.  Whichever you use, when you are looking at your call records, this tells you instantly if a problem caller is already being blacklisted, so you don’t need to wonder if you should add them to the blacklist.  The first example is probably more appropriate for older FreePBX systems that didn’t display the Userfield in the call detail, while the second works much better in newer FreePBX installations.  I would not suggest using both, though there is no harm if you do.

Keep in mind that any time you replace a context in /etc/asterisk/extensions_override_freepbx.conf, it is your responsibility to make sure it “tracks” any changes to the original context in /etc/asterisk/extensions_additional.conf.  So, after any major FreePBX upgrade, you should take a look at the original [app-blacklist-check] context (and the [cidlookup] context, if you have modified that) and make sure that they have not changed, and if they have, that you make the same changes to your replacement contexts.

One additional point – at the top of each of the original contexts, there is an “include” statement that we suggest you remove when you copy the context to /etc/asterisk/extensions_override_freepbx.conf, for example, “include => app-blacklist-check-custom“.  You might wonder if you could create a context named app-blacklist-check-custom in /etc/asterisk/extensions_custom.conf and copy the original context there.  But, for whatever reason, that just doesn’t seem to work, and there’s no real advantage to putting the copied context there anyway.

EDIT: If the above seems too complicated, there is an alternate technique that may work for some FreePBX users, provided you don’t care about receiving international calls.  See this thread on DSLReports for details.

Related articles:
Link: Asterisk: Blacklisting For Multiple Users
Forum thread: User-specific Caller ID/whitelist/blacklist in Asterisk/FreePBX

Link: Asterisk: Blacklisting For Multiple Users

Spotted this article referenced in a thread on DSLReports.com, and even though it’s from four years ago we thought it might be worth mentioning:

There are a number of tutorials for people trying to setup blacklisting for their Asterisk server, but they all seem to assume that there is only one user on the server, or at least all users want to share the same blacklist.

Since I host for multiple, unrelated people, they don’t necessarily want to share the same blacklist, so I had to come up with a configuration that would work for all customers.

Here are the changes I made (for Asterisk 1.4)

This may or may not need to be tweaked a bit to work with newer versions of Asterisk. Unfortunately, the thread on DSLReports leaves the impression that it might take a bit of work to integrate it into FreePBX, so you are on your own if you want to attempt that.

Full article here:
Asterisk: Blacklisting For Multiple Users (Lime Daley)
Related Link:
How to hack the FreePBX blacklist for better call blocking capability

Using the Raspberry Pi to control AC electric power

Notice
VERY IMPORTANT NOTE: THIS IS NOT A HOW-TO ARTICLE. This article explains how the author used a Raspberry Pi to control electric current. However, the author is NOT an electrician, and just because he did something doesn’t mean YOU should, particularly if you are unfamiliar with how to wire electrical devices safely. WIRING A DEVICE IMPROPERLY CAN RESULT IN FIRE, PROPERTY DAMAGE, BODILY INJURY, AND/OR DEATH! So DO NOT just blindly do what the author has done, unless you are certain you know what you are doing and are willing to take full responsibility for your own actions! This article is for INFORMATIONAL PURPOSES AND DISCUSSION ONLY, and is NOT intended to be a guide to building any device!

WE ARE NOT RESPONSIBLE IF YOU ATTEMPT TO BUILD ANYTHING BASED ON WHAT YOU SEE IN THIS ARTICLE AND INJURE YOURSELF OR HAVE PROPERTY DAMAGE AS A RESULT. STOP READING THIS ARTICLE NOW IF YOU ARE UNWILLING TO TAKE FULL RESPONSIBILITY FOR YOUR OWN ACTIONS!!!! AGAIN, THIS IS ONLY TO REPORT ON WHAT THE AUTHOR OF THE ARTICLE DID, AND WE ARE NOT SUGGESTING THAT YOU DO LIKEWISE, PARTICULARLY IF YOU DO NOT FULLY UNDERSTAND AND APPRECIATE THE DANGER OF WORKING WITH LIVE ELECTRIC CURRENT! PLEASE CONSULT WITH A LICENSED ELECTRICIAN BEFORE ATTEMPTING TO BUILD ANYTHING THAT WILL UTILIZE HOUSEHOLD ELECTRICAL CURRENT!

EDIT: This article is getting somewhat dated now, and while the principles shown in this article are still sound, they involve wiring or using devices that directly switch AC power. Also, the quality of the relay boards used is not always great – we have seen several instances of a single relay that simply fails to work correctly on a board of four or eight relays. And many people don’t have the skills to do this, or they are (with some justification) uncomfortable with doing anything that involves AC power. So we’ll just point out that there is another way to do this that doesn’t involve working with AC power directly, and it is explained in an article entitled How to use a Raspberry Pi to trigger wireless remote controlled outlets (and probably other wireless devices). That method has an additional convenience factor, in that the actual switched outlets can be at some distance from the Raspberry Pi. If you know next to nothing about electricity, perhaps consider going that route instead of trying what is shown here.

We were trying to figure out if a Raspberry Pi could be made to control a device that is powererd by 120 volts AC. Our first idea was to build a device based on this wiring diagram, which would have let us control two electric outlets individually, using GPIO pins 17 and 18 on the Raspberry Pi. We tried using a Solid State Relay rated at 25 Amps rather than the 40 Amp one shown in the diagram, but the wiring of the two devices is the same (click on the diagram to enlarge):

Pi Power Controller Wiring Diagram SSR

What we found was that the above method worked IF you get good Solid State Relays. Unfortunately, we purchased two of them, and only one of them would work with the Raspberry Pi. While the rated trigger voltage on the label is 3 – 32 volts DC, we found that one of the relays we purchased required something closer to four volts to trigger. We then found other reports where other purchasers of those types of relays have encountered similar issues. Some people could buy several and find they all worked, others were not so fortunate and would have issues like we did.

We returned the bad one for a refund, and searched for another solution. But we do note that some of those Solid State Relays such as the ones shown in the diagram can handle up to 40 Amps, assuming you use a good heat sink, and even the less expensive units we purchased can handle up to 25 Amps with a heat sink, so had we been trying to control a heavy load we might have been willing to order another one and try it. It’s quite possible that these relays would work better with a proper transistor and resistor added to the control circuit (and connecting one leg of the transistor to the +5 Volt supply on the Raspberry Pi), but since we aren’t electronic engineers we did not attempt to design such a circuit.

We then tried this, but only because there was nothing better available at the time. We no longer recommend this due to the low current-carrying capacity of the relays, and the availability of relay boards better suited for this application. For an example of a better solution, see How we made a Raspberry Pi controlled 8-outlet power box:

Pi Power Controller Wiring Diagram SainSmart

The above circuit uses a SainSmart 2 Channel 5V Solid State Relay Module Board. Unlike the Solid State Relays mentioned earlier, these devices do require a +5 volt power connection, but they only require a trigger voltage of 2.5V – 20V. We purchased one of those and tried it, and had no problem triggering it from the Raspberry Pi. However, we no longer recommend these due to the low current rating of the relays, as explained below.

SainSmart 2-Channel 5V Relay Module (NOT tested by us)
SainSmart 2-Channel 5V Relay Module (NOT tested by us)

The only downside is that these devices are only rated to handle 2 Amps (Volts x Amps = Watts, so if your voltage is 110 volts then that means you could in theory use up to a 220 watt load. Remember that motors and some other devices can draw many times their rated load for a second or two when starting up). We only wanted to switch power to devices that draw perhaps a couple dozen Watts at most, so the 2 Amp limitation wasn’t an issue. If you need to control something that draws more current, or you want to control a DC load, then perhaps this SainSmart 2-Channel 5V Relay Module for Arduino DSP AVR PIC ARM (pictured at right) that uses mechanical relays would work for you, but we have never attempted to use one of those, so cannot comment on whether or how well those would work. (EDIT December 21, 2013:) We have discovered that the mechanical relay boards are wired a bit differently than the solid state ones, due to differences between the Arduino and the Raspberry Pi, so at a very minimum you would probably want to add something like a ULN2803A or ULN2003A integrated circuit (the first can handle 8 channels, the latter only 7) to shift the levels, and use a separate external power supply to power the relay coils, as shown in this diagram (which shows the 4-channel version of the mechanical relay board) and discussed in this thread (also this thread and this one). Alternately, you could use individual NPN transistors and resistors to shift the levels. We’ve also been made aware of the SupTronics Expansion Board Made for Raspberry Pi that among other things provides an “8-channel darlington Driver chip allowing to control electronic circuits which require more current to drive them”, that might be suitable for driving one of these relay boards — it uses a ULN2803A integrated circuit (see full details here, and please note that we have not tested one of these boards to see if it would work in this application). We are not electronic engineers, but suffice it to say that the Raspberry Pi GPIO pins send +3.3 volts when turned on, whereas the Arduino sinks current to ground when on, and the mechanical relay board was definitely designed to work with the Arduino, not the Raspberry Pi.

EDIT (October 16, 2016): Although the SainSmart boards were designed for use with Arduinos and not Raspberry Pis, there now is a relay board available that was designed for use with the Raspberry Pi. You can read a review of it here: ModMyPi PiOT Relay Board for Raspberry Pi, or you can watch one of these videos:

Or, just visit the manufacturer’s page for the ModMyPi PiOT Relay Board.

EDIT (March 19, 2018): Another board that seems to work quite well with a Raspberry Pi, and that uses relays rated to handle 10 Amps looks like this:

Elegoo 8 Channel DC 5V Relay Module with Optocoupler
Elegoo 8 Channel DC 5V Relay Module with Optocoupler

This unit is sold on Amazon by Elegoo, and the only caveat is that it appears the GPIO pin states are inverted from what you’d expect. So, when a GPIO pin is at logical 0, the relay turns on, and switching it to logical 1 turns the relay off. However the relays have both normally open and normally closed contacts, so you should still be able to control whatever you want to control. If you can wrap your head around that, these work well – all you need to do is connect the Raspberry Pi to the 10 pin strip on the relay board: The Vcc pin on the relay board connects to 5 volts on the Pi (Pin 2), the Gnd pin on the relay board connects to any of the GND pins on the Pi (pin 25, for example), and the other pins (In1 through In8) connect to GPIO pins on the Pi (we suggest using the pins that are color coded green in the pinout diagram on this page).

An example of a power control box built using one of these relay modules can be seen here:  How we made a Raspberry Pi controlled 8-outlet power box

This YouTube video shows a guy using a similar relay board to the one shown above, though from a different seller. And, he’s also using different GPIO ports from the ones we would recommend using, just so his ribbon cable connection looks a bit neater. Regardless, the video does show that these types of relay boards can work quite well with a Raspberry Pi:

EDIT August 26-28, 2013: Someone (not us) posted a link to this article on Reddit, where in the comments it was criticized for showing a regular outlet in a circuit that can only draw 2 Amps. One commenter labeled this “a pretty irresponsible article” and noted that “using a 2 amp rated, but normal looking outlet with nothing to interrupt the circuit if it is overloaded sounds like a terrible idea and risks starting a fire. It is not hard to exceed 2 amps.” But as someone else noted, you can’t readily purchase a special outlet that is intended for use only with smaller loads. We only show the outlet to illustrate how a small device, for example a device powered by a typical “wall wart” power supply that only draws a few watts, could be controlled. The diagrams above are for conceptual and illustrative purposes only – we are NOT actually advising you to build any such circuit or to use that type of outlet, but if you nevertheless attempt to build such a thing and thereby assume all the risks of doing so, we at the very least suggest you affix a conspicuous label showing the maximum amperage and wattage ratings (for example: MAXIMUM RATING 2 AMPS / 220 WATTS PER OUTLET or whatever is appropriate for the circuit you build). It might also be a good idea to put some type of additional protection, such as a 2 amp fuse or circuit breaker, in each leg of the circuit between the hot side of the outlet and the Solid State Relay Module Board. Or, a far better alternative would be to substitute one of the mechanical relay boards with relays rated to handle 10 Amps (and of course, be careful to never connect anything drawing more than 10 Amps to an outlet). But again, this is not and was never intended to be a hardware construction article, so if you attempt to build anything such as this, please be sure you know what you are doing!

Also, it should go without saying that you should NEVER UNDER ANY CIRCUMSTANCES permanently connect a circuit of this type to your home’s electrical wiring. Don’t even think about it; it’s not safe to do that and probably would violate at least a dozen sections of the electrical codes where you reside. We shouldn’t even have to say this, but apparently the use of a regular outlet in the illustration led a couple of Reddit commenters to think we might actually be advocating something like that. Apparently they completely overlooked the cord and plug in the diagram, which would not be used in any kind of permanent installation. We are NOT advocating permanently connecting a circuit of this type directly to your home’s wiring because that would be an extremely stupid and dangerous thing to do, not to mention illegal!

We notice that the harshest Reddit commenters were apparently too cowardly to leave their most scathing comments in our comment section, where we might have addressed them more directly. Since we are not Reddit users (we read it very occasionally, but don’t post there) we will not further dignify some of their more irrational statements, particularly since the true intent of this article was to explore the methods that can be used to control a circuit of this type. In other words, the focus of this article is the software, not the hardware. But on that topic, for those that are interested in the hardware side of things, we’ll just note that SainSmart also makes these Solid State Relay Module Boards in 4-channel and 8-channel models. If you prefer the boards with mechanical relays rather than the solid state type, those also come in 4-channel and 8-channel models.

We were a little concerned that the power supply used to power the Raspberry might not support the additional load of the control circuits on the solid state relays. According to the description on the SainSmart site, the board we used requires 5 Volts DC at 160mA. According to this page on the Raspberry Pi web site, “Model B owners using networking and high-current USB peripherals will require a supply which can source 700mA (many phone chargers meet this requirement). Model A owners with powered USB devices will be able to get away with a much lower current capacity (300mA feels like a reasonable safety margin).” We aren’t using any USB peripherals at all, let alone high-current ones, and the power supply we are using produces 1000mA (1 Amp), so it would appear that the power consumption is well within the power supply’s capacity. And, we haven’t had any power issues. Still, it might not hurt to oversize your power supply a bit (use one rated for 2 Amps, for example), particularly if you are using the mechanical relays.

NOTE: Devices shown in the diagrams are NOT exactly to scale.

EDIT (September 21, 2016): If you do not wish to build your own device OR do not have the knowledge to do it safely, there is a commercial alternative available that may work. We are NOT recommending this, simply because we have neither owned nor tested one, and we do not know if it has received the necessary approvals for various countries, including wherever you may live. We’re simply alerting you that this product exists, but if you choose to buy one we assume no responsibility whatsoever for any outcome of your decision, good or bad.

The product is the IoT Power Relay from Digital Loggers (the same people that make the Atomic Pi) and its advertised features are as follows:

  • Universal control voltage 3-60VDC or 12-120VAC connects to Arduino, Raspberry Pi, PIC or other micro. Or connect directly to a 12V to 48VDC or even 120VAC circuit.

  • High voltage wiring and safety hazards are eliminated.

  • A single input signal switches four outlets: 2 normally on + 2 normally off.
  • Optical isolation, relay hysteresis and de-bounce protection add safety.

  • A large MOV clamps surges for clean  90-140VAC power.

  • The durable SPDT control relay is rated at 30/40A, >400,000 operations at 12A or 2 million+ operations at 5A.

  • A 12A thermal safety circuit breaker switch prevents overloads.

  • Standard 24″ C-13 detachable cord included free, cords up to 25′ are optional.

  • Professionally built and tested. Not a kit.  Be up and running in minutes.

IoT Power Relay from Digital Loggers
IoT Power Relay from Digital Loggers (NOT tested by us)

For those that have wanted a solution that did not require building from scratch, this might be it, at least in countries that use 120VAC as the standard voltage and use the standard USA/Canada style power outlet. We do not know at this time whether the scripts below would need any modifications to work with this device.

Controlling the device:

Controlling the device is a matter of turning the GPIO pins on or off. We came up with a couple of simple bash scripts to do this. Note that you MIGHT need to invert the on and off values for certain mechanical relay boards (send 1 for off and 0 for on, etc.):

For GPIO17 (filename /root/gpio17.sh):

#!/bin/bash

if [ -z $1 ]
then
    opt="toggle"
elif [ -n $1 ]
then
    opt=$1
fi

let "sleep = $RANDOM + 10000"
sleep "0.$sleep"

if [ $(pgrep gpio17.sh|wc -w) -gt "2" ]; then
    exit
fi

if [ ! -e "/sys/class/gpio/gpio17/value" ]
then
    echo "17" > /sys/class/gpio/export
    echo "out" > /sys/class/gpio/gpio17/direction
fi

case $opt in
    on)
        echo 1 > /sys/class/gpio/gpio17/value
        ;;
    off)
        echo 0 > /sys/class/gpio/gpio17/value
        ;;
    toggle)
        value=`cat /sys/class/gpio/gpio17/value`
        if [ $value -ne 0 ]
        then
            echo 0 > /sys/class/gpio/gpio17/value
        else
            echo 1 > /sys/class/gpio/gpio17/value
        fi
        ;;
    reboot)
        echo 0 > /sys/class/gpio/gpio17/value
        sleep 30
        echo 1 > /sys/class/gpio/gpio17/value
        ;;
    status)
        exit
        ;;
    *)
        echo "Invalid option - use on, off, toggle, or reboot (toggle is the default)."
        exit
        ;;
esac

sleep 3

And for GPIO18 (filename /root/gpio18.sh):

#!/bin/bash

if [ -z $1 ]
then
    opt="toggle"
elif [ -n $1 ]
then
    opt=$1
fi

let "sleep = $RANDOM + 10000"
sleep "0.$sleep"

if [ $(pgrep gpio18.sh|wc -w) -gt "2" ]; then
    exit
fi

if [ ! -e "/sys/class/gpio/gpio18/value" ]
then
    echo "18" > /sys/class/gpio/export
    echo "out" > /sys/class/gpio/gpio18/direction
fi

case $opt in
    on)
        echo 1 > /sys/class/gpio/gpio18/value
        ;;
    off)
        echo 0 > /sys/class/gpio/gpio18/value
        ;;
    toggle)
        value=`cat /sys/class/gpio/gpio18/value`
        if [ $value -ne 0 ]
        then
            echo 0 > /sys/class/gpio/gpio18/value
        else
            echo 1 > /sys/class/gpio/gpio18/value
        fi
        ;;
    reboot)
        echo 0 > /sys/class/gpio/gpio18/value
        sleep 30
        echo 1 > /sys/class/gpio/gpio18/value
        ;;
    status)
        exit
        ;;
    *)
        echo "Invalid option - use on, off, toggle, or reboot (toggle is the default)."
        exit
        ;;
esac

sleep 3

Be sure to make the scripts executable. If you want to control any of the other GPIO pins, just copy the text of either of the above scripts into a text editor (one that will not change the line endings) and then do a global search and replace for the pin number – for example, if you use the script for pin 18, and you want to control pin 4, just replace all occurrences of “18” with “4”, and then save the script as /root/gpio4.sh and make it executable. Besides 4, 17, and 18, other GPIO pin numbers you can use are 22, 23, 24, 25, and 27 – that’s on a Revision 2 board, but if you happen to have a Revision 1 board then substitute 21 for 27. And if you think the GPIO pin numbering on a Raspberry Pi makes absolutely no sense at all, you are not alone, since the GPIO pin numbers are not in any logical sequence, and bear no relationship whatsoever to the actual positions of the pins on the board. The best thing you can do is look at a chart such as this one to help you keep track of which pin is which.

(Strictly speaking, you may be able to control certain other pins on the Raspberry Pi as well, but the eight GPIO pins mentioned in the previous paragraph should be your first choices for any projects of this type, and controlling any of the others is beyond the scope of this article. Also, note that the wiring diagrams above show Revision 2 boards, which have slightly different pinouts from Revision 1 boards, although none of the pins actually used for wiring in those diagrams are different between revisions. This article assumes you have a Revision 2 board, so if you have Revision 1, substitute any references to pin 27 with pin 21).

The scripts accept four arguments – on, off, toggle, or reboot (actually it also accepts a fifth, status, but that is for a special purpose and it not really intended for use directly from a command prompt). toggle is the default if no argument is specified.

There is a small section at the top of each script that may confuse some readers:

let "sleep = $RANDOM + 10000"
sleep "0.$sleep"

if [ $(pgrep gpio17.sh|wc -w) -gt "2" ]; then
    exit
fi

That section delays a random amount of time (0.1 to 0.42767 seconds), then checks to see if the script is already running, without writing anything to the Raspberry Pi’s SD card (which could shorten the card’s lifespan if done too frequently). If the script is already running it bails out. While it is unlikely that a user would attempt to start the same script twice, this pretty much guards against it. That’s also the point of the “sleep 3” at the end of the script, which keeps devices from being toggled on or off too quickly. If you know of a better way to do this, feel free to modify the script, and also to post your suggested modifications in the comments (but, please do not suggest reading man pages. If that is all you can be bothered to offer, please just move along).

The reason we used two scripts for the two pins, rather than just one with an added option to specify which pin to control, is so that you could control the two different pins simultaneously without being denied access to one because the script is already running on the other.

The options should be pretty obvious:

on – turn the pin on
off – turn the pin off
toggle – if the pin is currently off, turn it on, and vice versa (this is the default if no option is specified)
reboot – turn the pin off for 30 seconds, then turn it on

The hidden one, status, is a do-nothing command that only makes sure that the pin is initialized, but does not change its state. It is meant to be used when you are calling this script from Asterisk. Yes, you can do that, once the above scripts are enabled and you know they are working properly!

Controlling the device from Asterisk/FreePBX:

This section assumes that the Raspberry Pi is running Asterisk for Raspberry Pi (RasPBX), though it should work with any other FreePBX-based distribution that runs on the Raspberry Pi. To allow Asterisk to control the GPIO pins, you could add the following lines to /etc/asterisk/extensions-custom.conf (note this requires a few custom recordings and a bit of additional configuration, which will be discussed in a moment):

[custom-picontrol]
exten => s,1,Set(TIMEOUT_LOOPCOUNT=0)
exten => s,n,Set(INVALID_LOOPCOUNT=0)
exten => s,n,Set(_IVR_CONTEXT_${CONTEXT}=${IVR_CONTEXT})
exten => s,n,Set(_IVR_CONTEXT=${CONTEXT})
exten => s,n,Set(__IVR_RETVM=)
exten => s,n,GotoIf($["${CDR(disposition)}" = "ANSWERED"]?skip)
exten => s,n,Answer
exten => s,n,Wait(1)
exten => s,n(skip),Set(IVR_MSG=custom/please-enter-rpi-pin)
exten => s,n(start),Set(TIMEOUT(digit)=3)
exten => s,n,Set(PIGPIOPIN=Background(${IVR_MSG}))
exten => s,n,ExecIf($["${IVR_MSG}" != ""]?Background(${IVR_MSG}))
exten => s,n,WaitExten(5,)
exten => 4,1(ivrsel-4),Set(PIGPIOPIN=4)
exten => 4,n,Goto(custom-validpipin,s,1)
exten => 17,1(ivrsel-17),Set(PIGPIOPIN=17)
exten => 17,n,Goto(custom-validpipin,s,1)
exten => 18,1(ivrsel-18),Set(PIGPIOPIN=18)
exten => 18,n,Goto(custom-validpipin,s,1)
exten => 22,1(ivrsel-22),Set(PIGPIOPIN=22)
exten => 22,n,Goto(custom-validpipin,s,1)
exten => 23,1(ivrsel-23),Set(PIGPIOPIN=23)
exten => 23,n,Goto(custom-validpipin,s,1)
exten => 24,1(ivrsel-24),Set(PIGPIOPIN=24)
exten => 24,n,Goto(custom-validpipin,s,1)
exten => 25,1(ivrsel-25),Set(PIGPIOPIN=25)
exten => 25,n,Goto(custom-validpipin,s,1)
exten => 27,1(ivrsel-27),Set(PIGPIOPIN=27)
exten => 27,n,Goto(custom-validpipin,s,1)
exten => i,1,Set(INVALID_LOOPCOUNT=$[${INVALID_LOOPCOUNT}+1])
exten => i,n,GotoIf($[${INVALID_LOOPCOUNT} > 3]?final)
exten => i,n,Set(IVR_MSG=custom/sorry-not-valid-rpi-gpio)
exten => i,n,Goto(s,start)
exten => i,n(final),Playback(no-valid-responce-transfering)
exten => i,n,Goto(app-blackhole,hangup,1)
exten => t,1,Set(TIMEOUT_LOOPCOUNT=$[${TIMEOUT_LOOPCOUNT}+1])
exten => t,n,GotoIf($[${TIMEOUT_LOOPCOUNT} > 3]?final)
exten => t,n,Set(IVR_MSG=no-valid-responce-pls-try-again&custom/please-enter-rpi-pin)
exten => t,n,Goto(s,start)
exten => t,n(final),Playback(no-valid-responce-transfering)
exten => t,n,Goto(app-blackhole,hangup,1)
exten => return,1,Set(_IVR_CONTEXT=${CONTEXT})
exten => return,n,Set(_IVR_CONTEXT_${CONTEXT}=${IVR_CONTEXT_${CONTEXT}})
exten => return,n,Set(IVR_MSG=custom/please-enter-rpi-pin)
exten => return,n,Goto(s,start)
exten => h,1,Hangup
exten => hang,1,Playback(vm-goodbye)
exten => hang,n,Hangup

[custom-validpipin]
exten => s,1,Set(TIMEOUT_LOOPCOUNT=0)
exten => s,n,Set(INVALID_LOOPCOUNT=0)
exten => s,n,Set(_IVR_CONTEXT_${CONTEXT}=${IVR_CONTEXT})
exten => s,n,Set(_IVR_CONTEXT=${CONTEXT})
exten => s,n,Set(__IVR_RETVM=)
exten => s,n,GotoIf($["${CDR(disposition)}" = "ANSWERED"]?skip)
exten => s,n,Answer
exten => s,n,Wait(1)
exten => s,n(skip),Set(IVR_MSG=custom/rpi-gpio-pin-state-selection)
exten => s,n(start),Set(TIMEOUT(digit)=3)
exten => s,n,ExecIf($["${IVR_MSG}" != ""]?Background(${IVR_MSG}))
exten => s,n,WaitExten(5,)
exten => 0,1(ivrsel-0),Set(PIPINSTATE=off)
exten => 0,n,Goto(custom-pincontrol,s,1)
exten => 1,1(ivrsel-1),Set(PIPINSTATE=on)
exten => 1,n,Goto(custom-pincontrol,s,1)
exten => 2,1(ivrsel-1),Set(PIPINSTATE=toggle)
exten => 2,n,Goto(custom-pincontrol,s,1)
exten => 3,1(ivrsel-1),Set(PIPINSTATE=reboot)
exten => 3,n,Goto(custom-pincontrol,s,1)
exten => 4,1(ivrsel-1),Set(PIPINSTATE=status)
exten => 4,n,Goto(custom-pincontrol,s,1)
exten => i,1,Set(INVALID_LOOPCOUNT=$[${INVALID_LOOPCOUNT}+1])
exten => i,n,GotoIf($[${INVALID_LOOPCOUNT} > 3]?final)
exten => i,n,Set(IVR_MSG=no-valid-responce-pls-try-again)
exten => i,n,Goto(s,start)
exten => i,n(final),Playback(no-valid-responce-transfering)
exten => i,n,Goto(app-blackhole,hangup,1)
exten => t,1,Set(TIMEOUT_LOOPCOUNT=$[${TIMEOUT_LOOPCOUNT}+1])
exten => t,n,GotoIf($[${TIMEOUT_LOOPCOUNT} > 3]?final)
exten => t,n,Set(IVR_MSG=no-valid-responce-pls-try-again&custom/rpi-gpio-pin-state-selection)
exten => t,n,Goto(s,start)
exten => t,n(final),Playback(no-valid-responce-transfering)
exten => t,n,Goto(app-blackhole,hangup,1)
exten => return,1,Set(_IVR_CONTEXT=${CONTEXT})
exten => return,n,Set(_IVR_CONTEXT_${CONTEXT}=${IVR_CONTEXT_${CONTEXT}})
exten => return,n,Set(IVR_MSG=custom/rpi-gpio-pin-state-selection)
exten => return,n,Goto(s,start)
exten => h,1,Hangup
exten => hang,1,Playback(vm-goodbye)
exten => hang,n,Hangup

[custom-pincontrol]
exten => s,1,Noop(GPIO pin selected is ${PIGPIOPIN} and pin state is ${PIPINSTATE})
exten => s,n,System(sudo /root/gpio${PIGPIOPIN}.sh ${PIPINSTATE})
exten => s,n,Playback(custom/pin)
exten => s,n,SayNumber(${PIGPIOPIN})
exten => s,n,Playback(en/ha/is)
exten => s,n,ExecIf($["${SHELL(cat /sys/class/gpio/gpio${PIGPIOPIN}/value):0:1}" = "0"]?Playback(en/ha/off):Playback(en/ha/on))
exten => s,n,Goto(app-blackhole,hangup,1)
exten => h,1,Hangup

The [custom-picontrol] context above actually allows you to enter any of the possible GPIO pins (available to the user) on the Raspberry Pi, but in our example we’re only using pins 17 and 18, so if you don’t plan on using any other GPIO pins, you may want to remove all the lines that start with exten => N, where N is any number other than 17 or 18. The first two contexts are based on FreePBX IVR logic, except that instead of using the selection to transfer to an extension or other destination, the choices made are stored in variables for use by the [custom-pincontrol] context.

In order for this to work, there are a few extra steps you must take. First, you must give Asterisk permission to run the scripts. Run the visudo command as root, and use it to add these lines to the end of /etc/sudoers:

asterisk ALL = NOPASSWD: /root/gpio17.sh
asterisk ALL = NOPASSWD: /root/gpio18.sh

If you want to allow Asterisk to control all the GPIO pins rather than just 17 and 18, here’s a complete list of the lines to add to /etc/sudoers. Note that you must create the additional scripts and make them executable:

asterisk ALL = NOPASSWD: /root/gpio4.sh
asterisk ALL = NOPASSWD: /root/gpio17.sh
asterisk ALL = NOPASSWD: /root/gpio18.sh
asterisk ALL = NOPASSWD: /root/gpio22.sh
asterisk ALL = NOPASSWD: /root/gpio23.sh
asterisk ALL = NOPASSWD: /root/gpio24.sh
asterisk ALL = NOPASSWD: /root/gpio25.sh
asterisk ALL = NOPASSWD: /root/gpio27.sh

You must also create some system recordings and place them in the /var/lib/asterisk/sounds/custom directory. These can be added using the FreePBX System Recordings module, which is actually the preferred way because it will make sure all the permissions are set correctly. These are the four new recordings you need, and the suggested scripts:

please-enter-rpi-pin.wav: “Please enter the Raspberry Pi GPIO pin number you wish to control:”
rpi-gpio-pin-state-selection.wav: “Press zero to turn the GPIO pin off, one to turn it on, two to set it to the opposite of its current state, three to initiate a reboot sequence, or four to hear the current status of the pin.”
sorry-not-valid-rpi-gpio.wav: “I’m sorry, that is not a valid Raspberry Pi GPIO pin number. Please try again.”
pin.wav: “Pin”

If you are handy with an audio editor such as Audacity, you can probably slice the word Pin off of one of the existing recordings that start with the word “Pin” (found in /var/lib/asterisk/sounds/en for English-language speakers). For the others, you can record them yourself, or you could perhaps use text-to-speech software to generate them. There’s also the option of using flite text-to-speech synthesis if it is installed on your system, but you’ll need to modify the contexts accordingly (we don’t care for the sound of flite, so you are on your own with that).

Finally, you must go into FreePBX and under Admin/Custom Destinations, add a Custom Destination called “Raspberry Pi control”, then give it this destination:

custom-picontrol,s,1

Then go into Applications/Misc Applications and add a new Misc Application called “Raspberry Pi Control” or whatever you want. Give it an extension number you want to use when controlling pins on your Raspberry Pi – we used 774 (“RPI” on a standard touch-tone keypad). For the destination, select “Custom Destinations” and “Raspberry Pi control”, then apply the changes and you should be all set.

Other ways to control the pins:

There are many other ways you can control the pins. You can even do it from another computer on your network. For example, we have set up SSH Passwordless Logins from another computer on our local network. Having done that, we can create scripts on that computer that look like this (note you do NOT put these on the Raspberry Pi!):

In ~/gpio17.sh place these two lines:

#!/bin/bash
ssh root@IP_address_of_Raspberry_Pi "/root/gpio17.sh $1"

In ~/gpio18.sh place these two lines:

#!/bin/bash
ssh root@IP_address_of_Raspberry_Pi "/root/gpio18.sh $1"

Replace IP_address_of_Raspberry_Pi with the IP address of your Raspberry Pi – of course, this works best if the Raspberry Pi is always on the same IP address.

Now we can run the bash scripts from a another system, just as if we were logged into the Raspberry Pi. But the beauty of this is that you can call those scripts from other software on the system. Let’s say the other system is a home theater PC, and it has a ~/.lircrc file to accept commands from the remote. You could possibly add lines like this (note these are dependent on the remote you are using, and are just examples):

begin
 prog = irexec
 button = KEY_RED
 config = ~/gpio17.sh &
 repeat = 0
endbegin
 prog = irexec
 button = KEY_BLUE
 config = ~/gpio18.sh &
 repeat = 0
end

Now every time you press the red button on the remote, GPIO17 on the Raspberry Pi would toggle to the opposite of its current state (since no option is specified). And if you pressed the blue button, GPIO18 would toggle. So you could use a remote on a different system to send commands to the Raspberry Pi to power a device on or off. Or you could create a script or program that switches things on or off at certain times. We’ve actually done this so we know it works!

There is software available that allows you to use a web interface to control the GPIO pins, such as BerryIO and WebIOPi. It seems that the possibilities are endless. I could envision building something like an automatic lawn watering system controller that could go out and download the weather report, and then decide to water or not water based on the probability of significant amounts of rain. That’s just one example of the sort of thing you could do if you have the ability and the expertise.

Again, should you foolishly ignore our advice to not try building anything like this unless you know how to protect yourself when working with household electrical current, PLEASE remember to use extreme caution! We would really hate to see anyone kill or injure themselves, or set their house on fire (but we will not be responsible if you do that, because we’ve warned you every way we can think of!).

 

Asterisk on a Raspberry Pi – which distribution is best?

Portions of this article were UPDATED July 20, 2016, mostly to include information about Raspivo.

To the best of our knowledge there are five projects that will allow you to run a PBX on a Raspberry Pi. They are:

In this discussion we are only going to consider the first four, because FusionPBX runs on top of FreeSWITCH, not Asterisk. And we have nothing against FreeSWITCH, but it’s never been big among home users and experimenters. Perhaps that should change, but for now we just want to consider the Asterisk-based distributions.

It does not seem as though µElastix ever really caught on with a significant group of English-speaking users, and therefore it would be difficult to offer any sort of opinion. But we will note that new users and those not all that familiar with Linux may have a bit more trouble with the installation process, since there is no image file provided as is the case for some other distributions. One potential advantage of µElastix is that it will run on a Raspberry Pi, PicoSam, or Mcuzone, though you are not likely to run into the latter two boards anywhere in North America.

As for Incredible PBX, this takes the typical Nerd Vittles/PBX in a Flash “throw in everything but the kitchen sink” approach, but then offers this ominous-sounding advice:

Here’s everything you need to know about security for Incredible Pi:

1. ALWAYS RUN INCREDIBLE PI BEHIND A SECURE HARDWARE-BASED FIREWALL/ROUTER
2. NEVER EXPOSE ANY INCREDIBLE PI PORTS DIRECTLY TO THE INTERNET
3. NEVER MAP INBOUND INTERNET PORTS FROM YOUR FIREWALL TO INCREDIBLE PI

What this basically means is that you can’t have any off-site extensions that register with your Asterisk server, if you heed their warning.  Well, you CAN, but not in any way that’s convenient for end users.  The problem apparently is that a few years ago someone connected with that project got hold of an article or two where someone got a huge phone bill by having an unsecured PBX, and had a major freakout about it.  There were probably several security failures associated with those incidents, but here is our question:  Since nobody in ANY other PBX project we’ve ever encountered gives advice like this, does this mean that Incredible PBX is incredibly insecure by design, and the only way to properly secure it is to take extraordinary steps such as these?

We’re not saying that all of this advice is out of line – the first point is probably a very good idea whenever possible – but most home users will be doing that anyway.  But it’s we particularly take issue with.  If you want to have any external extensions, you pretty much need to forward UDP ports 5060 and 10000-20000 to your Asterisk server.  And the Incredible PBX people specifically tell you not to do that, rather than recognizing that for some users that is simply not a viable option.

The other issue we have with Incredible PBX is that it includes a lot of what we would consider frivolous add-ons.  The main reason people generally install a PBX is because they want to use it to make phone calls, and perform a few other basic functions such as record voicemail, let callers select a destination from an auto-attendant, and so on.  All of these basic functions are provided by FreePBX, and all the other add-ons are pretty much useless unless you are just installing a PBX to play with features.  We can just about guarantee you that 99 percent of your users will not care that they can dial a code and get tide reports, or some similar nonsense.  On a regular server that has a lot of CPU power and storage space, having a bunch of extras may not be a problem.  On a Raspberry Pi, however, you are probably going to want a lean, trim installation that doesn’t get in the way of the basic functionality of a PBX.

I’ve seen reports in mid-2016 that Incredible PBX will soon (and perhaps already does) offer a menu at installation where you can select which features you want. However you will need to choose carefully because if you reject an option and then later decide you want it, you might need to reinstall from scratch to get it. New users might not know which features are actually useful and which are needless bloat, but at least it appears some effort is underway to stop forcing users to take all or nothing.

Raspivo is based on XiVO, which has been around for a while but was relatively unknown in the English-speaking world until fairly recently. However it has generated a lot of interest due to users desiring an alternative to FreePBX, which seems to be getting less “free” (in all senses of that word) as time goes by. There is a discussion about XiVO on DSLReports that you may wish to read, which in turn contains several other useful links. My understanding is that the “official” English language translation of the installation instructions are somewhat out of date, so you may find that RonR’s instructions on DSLReports are easier to follow. Like FreePBX, XiVO is a GUI interface for Asterisk, so any custom dialplan you have written for another build of Asterisk should be usable (perhaps with minor modification) in Raspivo. It appears that you must have at least a Raspberry Pi 2 or newer to run Raspivo.

If you have no experience at all with software PBX’s and are just getting your feet wet, but you are not unfamiliar with programming, XiVO is the one I’d suggest. It makes repetitive tasks easier but doesn’t get in your way when you want to customize your system to the same degree that FreePBX does. However if you just want everything to be as easy as possible, and you never want to do any dialplan customizations (or only very limited ones), then you may want to consider Asterisk for Raspberry Pi, also known as RasPBX.

The RasPBX distribution includes Asterisk and FreePBX, with additional scripts that will optionally let you install HylaFAX and/or Fail2Ban. There is also a related version of this software for the BeagleBone Black. This software is relatively easy to install, comes with no ominous security warnings, and doesn’t include a lot of “bloatware”, which we think is a definite advantage. They also have a semi-active discussion forum where you can find several installation and usage tips. And it is possible to run RasPBX from an External USB HDD or Thumb Drive, in case you are worried that running a PBX off of an SD card might not be reliable, although there are ways to minimize writes to the SD card if you prefer not to have the added power drain of another device.

We realize that none of these distributions are absolutely perfect, and everyone will have their own reasons for picking one over another. The PBX in a Flash forum used to include a Raspberry Pi board, but it was apparently lost in their “Great server crash of 2013”, and they never bothered to reinstate it. So it seems that for them, the Raspberry Pi is just one of many platforms they are attempting to support, and it does not appear to us that they are making much of an attempt to optimize their software specifically for the Raspberry Pi. We might receive a few less than gracious comments for saying that, but that’s simply our observation, and others are free to disagree – we just recall the old saying, “Jack of all trades, master of none” and feel it might apply in the case of putting out a version of Incredible PBX for the Raspberry Pi that includes pretty much everything that the versions intended for larger servers include. For performance reasons, we’d prefer to stick with a distribution designed for the Raspberry Pi from the ground up, and therefore our preference has always been Asterisk for Raspberry Pi / RasPBX, though nowadays we’d suggest that anyone that wants to have complete control over their system might also consider Raspivo. Just be aware that the learning curve with Raspivo might be a bit steeper.

If you disagree, feel free to try any of the other distributions mentioned. That’s the nice thing about having choices – you can try various programs until you find one that meets your needs, and maybe even your wants.

One final point – since this article was originally written in 2013, new versions of the Raspberry Pi have appeared, and some of the above-mentioned software may have been updated to only run on newer models. Or they may run, but only painfully slowly, if you have an original Raspberry Pi. In particular, it appears that Raspivo will only run on the Raspberry Pi 2 or newer. So if you have a first-generation Raspberry Pi, pay attention to the system requirements for the software you are downloading, because you might need to seek out an alternate or older version of the software.

Add voicemail transcriptions to e-mail notifications in FreePBX

This comes from a post in the PBX in a Flash forum by user matt91 and was slightly edited, but will probably work on most FreePBX installations of recent vintage. Note that at one time you could get 30 seconds of voice transcribed but now it is only 15, but that still may be enough to help you quickly decide if you want to listen to the full message. If you are not running PBX in a Flash then open the batch file in a text viewer before you run it and make sure it’s not going to do something you don’t want it to do, and run it at your own risk.

1. Log into your server via SSH as root and…

cd /root
wget -N http://www.deltaend.net/pbx/installmp3stt.sh
chmod 0755 installmp3stt.sh
./installmp3stt.sh

2. In FreePBX, choose Settings -> Voicemail Admin -> Settings, make the following changes, then click Submit and Reload FreePBX.

format -> wav
mailcmd -> /usr/sbin/sendmailmp3

3. Leave yourself a voicemail and you should see the first 15 seconds of the voicemail transcribed for you.

Proof of concept: Automatically transfer Google Voice voicemail to Asterisk voicemail

 

Important
This article is a guest post. We may not be able to answer questions about this article.

The following should be considered proof-of-concept material. Feel free to use and/or modify it at your own risk.

The problem: You have Google Voice calls coming into an Asterisk server but even though you take care to answer calls when they arrive, every so often some hiccup causes voicemails to be left in Google Voice’s voicemail, and no one checks those. The solution: Transfer those voicemails to Asterisk’s voicemail box for that user.

The following assumes that there is already an active voicemail box established for the target user.

Prerequisites: php-xml (do yum install php-xml on a Centos-based system). Also, go to the Google-Voice-PHP-API page on GitHub and grab the file GoogleVoice.php – be sure to get the Raw version of the file. It is suggested that you place it your root directory, and make it executable. Note that if you have downloaded this file in the past, you should check to make sure you have the most recent version, since older versions available prior to June, 2013 did not include the ability to download voicemails.

Then in the same directory create a new file. Call it anything you want but give it a .php extension:

<?php

include('/root/GoogleVoice.php');

// NOTE: If you get errors from GoogleVoice.php, try installing the php-xml package
// You must change the name and password on the following line. NOTE: Full email address required.
$gv = new GoogleVoice('gv_user@gmail.com', 'gv_account_password');
// On the next line insert the extension number of the target voice mail box.  Must have voicemail enabled!
$vmbox = '1111';
// On the next line specify an email address for delivery of new voicemail notification.  Use $email=FALSE; if you don't want this.
// Note that this will not send the voicemail as an attachment so if you want that, do it from within the Google Voice account.
$email="username@gmail.com";

// Don't change anything below unless you know what you are doing!

// Set path to user's mailbox
$dir = '/var/spool/asterisk/voicemail/default/'.$vmbox.'/INBOX/msg';

// Set flag that determines if message waiting indications will be updated
$mwi = FALSE;

// Get data on all unread Google Voice voicemail messages into array.
$voice_mails = $gv->getUnreadVoicemail();
$msgIDs = array();
$keys = array_keys($voice_mails);

// process each available message
foreach($voice_mails as $v) {
	//	echo 'Message id: '.$v->id.' from '.$v->phoneNumber.' on '.$v->displayStartDateTime.': '.$v->messageText."<br><br>\n";

	// Downloads individual voicemail
	// Uses getVoiceMailMP3 function added to GoogleVoice.php - WILL FAIL with unmodified GoogleVoice.php 
	$mp3 = $gv->getVoicemailMP3($v->id);

	// construct temporary filenames used
	$mp3file = $v->id.".mp3";
	$wavfile = $v->id.".wav";

	// write temporary mp3 file to disk
	$fh = fopen($mp3file, 'w') or die("can't open file");
	fwrite($fh, $mp3);
	fclose($fh);

	// convert mp3 to temporary wav file
	system("mpg123 -q -w mp3towavtmp.wav ".$mp3file);

	// convert wav file to format required by Asterisk
	system("sox mp3towavtmp.wav -r 8000 -c 1 ".$wavfile." vol 3 dB");

	// If caller's number starts with +1 strip it
	$number=$v->phoneNumber;
	if (substr($number, 0, 2) == '+1') {
		$number=substr($number, 2);
	}

	// Calculate approximate duration of file from file size
	$duration=(int) (filesize($wavfile)/16000);

	// Construct Message Information file for Asterisk - following must be one long continuous line!
	$txt=";\n; Message Information file\n;\n[message]\norigmailbox=$vmbox\ncontext=macro-vm\nmacrocontext=ext-local\nexten=s-NOANSWER\nrdnis=unknown\npriority=2\ncallerchan=\ncallerid=<$number>\norigdate=$v->displayStartDateTime\norigtime=".substr($v->startTime,0,10)."\ncategory=\nflag=\nduration=$duration\n";

	// Find next unused voicemail file number in Asterisk voicemail directory
	$exists = TRUE;
	$i = 0;
	while ($exists) {
		$file=$dir.substr("000$i",-4).'.txt';    
		$exists = file_exists($file);
		$i++;
	}
	$i--;

	// $file will contain path and base filename of voicemail files, without extension
	$file = $dir.substr("000$i",-4);

	// Write Message Information file for this voicemail
	$fh = fopen($file.".txt", 'w') or die("can't open file");
	fwrite($fh, $txt);
	fclose($fh);

	// Change owner and group of file to asterisk
	chown($file.'.txt', "asterisk");
	chgrp($file.'.txt', "asterisk");

	// Move wav file to voicemail directory with proper filename
	rename($wavfile, $file.".wav");

	// Change owner	and group of file to asterisk
	chown($file.'.wav', "asterisk");
	chgrp($file.'.wav', "asterisk");

	// Mark message read in Google Voice so we don't read it again
	if(!in_array($v->id, $msgIDs)) {
		// Mark the message as read in your Google Voice Voicemail.
		$gv->markMessageRead($v->id);
		$msgIDs[] = $v->id;
	}

	// If email address specified construct and send email to user
	// Wanted option to attach voicemail but couldn't figure out how to do it correctly. uuencode does NOT work.
	if ($email) {
		// Construct email text
		$txt="There is a new voicemail in mailbox $vmbox that was imported from Google Voice's voicemail system:\n\n\tFrom:\t$number\n\tLength:\t$duration seconds\n\tDate:\t$v->displayStartDateTime\n";
		if ($v->messageText) {
			$txt=$txt."\tTranscription:\t$v->messageText\n";
		}
		$txt=$txt."\nDial *98 to access your voicemail by phone.\n";
		$i++;
		`echo "$txt" | mail -s "New message $i in mailbox $vmbox" "$email"`;
	}

	// Remove temporary files
	unlink($mp3file);
	unlink('mp3towavtmp.wav');

	// Set flag to indicate message waiting indication needs to be reset
	$mwi = TRUE;

}

// If messages were processed tell Asterisk to reset message waiting indications
// This may not be the best way to do this but only way I know
if ($mwi) {
	`/usr/sbin/asterisk -rx "voicemail reload"`;
}

?>

After you have changed the information at the top of the above code so it is correct for your installation, save it to a file with the extension .php and don’t forget to make it executable. Remember, this is proof-of-concept code, and we do not guarantee that it is ready for use in a production environment. It could probably benefit from additional error checking and possibly other enhancements.

You may want to call the above file on a schedule, perhaps every 15 minutes or every hour, depending on how urgently you want to receive Google Voice voicemails. I would not do it too often because you never know if Google would feel you are abusing their system with very frequent accesses. Note that when you call the script you’ll need to call it using php, for example:

php scriptname.php

and if that doesn’t work try adding the -f option after “php” but before the script name. Also, if you are running multiple copies of this script from a bash script (because you are collecting voicemail for more than one Google Voice user) then use a sleep statement between executions (such as sleep 30), otherwise you may see errors such as this:

PHP Fatal error: Uncaught exception ‘Exception’ with message ‘Could not log in to Google Voice with username: user@gmail.com’ in /root/GoogleVoice.php:67

Note that when this inserts voicemails into the Asterisk voicemail directory, it is not quite the same as when using a user leaves a voicemail. The known differences are:

  • When a user leaves a voicemail, the audio is saved in two files, a larger one with a .wav extension and a smaller one with a .WAV extension. The larger one is standard .wav format but the smaller seems to be some sort of GSM file, and I cannot figure out how to get SOX to create a compatible file, so I just don’t bother with it. It doesn’t seem to be needed anyway.
  • While this will let you send a notification e-mail to the message recipient, it does not let you attach the mp3 or wav file to the email. Again, don’t know how, but remember you can configure Google Voice to send a notification (with out without audio file attachment) when someone leaves a voicemail.

I hope someone will expand upon this to create something a bit more robust.

FreePBX: Receive a daily e-mail of the Call Detail Report for the previous day

If you use FreePBX you might have wished that you could get a daily report of call activity e-mailed to you, if only to remind you to check for suspicious activity, so that you don’t get hacked and not know about it for weeks because you fell out of the habit of checking the log. It turns out that there is a fairly easy way to do it, as explained in a post by user Boolah in this thread in the PBX in a Flash forum:

EDIT (December, 2017): The method shown at that link and below doesn’t work at all in newer versions of FreePBX. It seems like every new version requires some tweaking. This is the line that works in FreePBX 14:

/usr/bin/mysql -u freepbxuser -ppassword -e "select calldate AS Timestamp, clid AS CallerID, did AS DID, dst AS Destination, disposition AS Disposition, duration AS Duration, userfield AS Userfield from cdr where calldate > date_sub(now(), interval 24 HOUR)" -H asteriskcdrdb | mail -a "From: PBX <asterisk@youraddress.com>" -a "Content-Type: text/html" -s "Custom Call Report" you@youremail.com

The above is all one long line. You must replace the above values:

-u freepbxuser -ppassword (that’s not a typo – there really is NO SPACE after the -p) – replace freepbxuser and password with the correct values for YOUR system. You will usually find these in one of two places. You can look in /etc/amportal.conf and look for the variables AMPDBUSER and AMPDBPASS — these will usually be near the bottom of the file in newer installs, in a “— CATEGORY: Bootstrapped or Legacy Settings —” section, but they can be anywhere in the file.

Another place they may be found is in the file /etc/freepbx.conf — in that file, look for lines similar to:

$amp_conf[‘AMPDBUSER’] = ‘freepbxuser’;
$amp_conf[‘AMPDBPASS’] = ‘password’;

Those will give you the values to use to replace freepbxuser and password

-a “From: PBX <asterisk@youraddress.com>” – replace asterisk@youraddress.com with a valid outgoing email address for your system. If you have a Dynamic DNS address, you may be able to use that after the @ in the email address. It mostly depends on how you send outgoing email from your system. Note that using “root” before the @ sign may not work, particularly if you are routing mail through an ISP’s mail servers – one major ISP now appears to silently drop any email that appears to originate from root@anything, so use “asterisk” or “pbx” or something else other than “root”.

-s “Custom Call Report” you@youremail.com – replace you@youremail.com with the address you want the reports emailed to.

What follows is the rest of the original article. The mysql line shown there probably will not work, unless perhaps you are running a very old version of FreePBX (end of edit).

This is very basic, but should get you the info you need. Add it as a cron to run once a day and it will email the date/time of the call along with the CNAM and CID for all incoming calls for the previous day:

mysql -u root -ppassw0rd asteriskcdrdb -e 'SELECT calldate, clid FROM cdr WHERE DATE(calldate) = SUBDATE(CURDATE(), 1) AND did <> ""' | mail -s "Yesterday's Calls" you@youremail.com

Replace the you@youremail.com with your actual email address.

When copying the above, note that it’s all one single line, even though it wraps in this blog post, and also beware that WordPress likes to change single and double quotation marks into the “prettified” versions, so make sure you change those characters back to the plain old ASCII versions or it won’t work correctly. Or, you could just visit the thread mentioned above and copy the line from there.

Recent Posts

Recent Comments

Archives

Categories

Meta

GiottoPress by Enrique Chavez