How to use a Raspberry Pi as a print server

This post is designed for people who want to share a simple USB printer, such as this receipt printer, over the network.

Usually, you just connect up the printer to the computer like this:

2015-04-rpi-printer1

But if you are sending the print jobs from a central server, you would instead follow these steps, and hook up a Raspberry Pi near the printer to pass on the print-outs for you:

2015-04-rpi-printer2

This post will show you a very fuss-free way to do this. Because of its simplicity, if you have multiple computers printing (read: you need a server that can spool), or need two-way communication with the printer, then this setup will not be sufficient for your use case.

One-off setup

If your printer is /dev/usb/lp0, then the command to run is:

nohup nc -klp 9100 > /dev/usb/lp0 2> /dev/null&

There is quite a lot going on in this command, so I’m going to break it down into parts and explain what each one does.

nohup
Lets the command keep running after you log-out.
nc -klp 9100
Listens on port 9100 (-lp), and returns to listening after each connection (-k)
> /dev/usb/lp0
Redirects any incoming data to the printer device
2> /dev/null
Suppresses errors by sending them to /dev/null
&
Runs the command in the background so that you can keep using the terminal.

Run every boot

Simply schedule the command in cron as a @reboot task.

crontab -e

And add the line:

@reboot nohup nc -klp 9100 > /dev/usb/lp0 2> /dev/null&

Note that if you reboot the printer, you will also need to reboot the raspberry pi to get it to reconnect without logging in!

Send some tests

From a computer somewhere else on the network, send a test print-out:

echo "Hello world" | nc 10.x.x.x 9100

If the target printer is a thermal receipt printer, then you could also use escpos-php to send it more elaborate commands:

<?php
$fp = fsockopen("10.x.x.x", 9100);
/* Print a "Hello world" receipt" */
$printer = new Escpos($fp);
$printer -> text("Hello World!\n");
$printer -> cut();
fclose($fp);

How to run Tetris on your Raspberry Pi

This is a simple walkthrough on how to install my Tetris clone, Blocks, on a Raspberry Pi.

On most computers running Debian (or Raspbian in the case of the Raspberry Pi), it’s as simple as clone, compile, run:

sudo apt-get install libncurses5-dev doxygen
git clone https://github.com/mike42/blocks
cd blocks
make
./bin/blocks

If you have any issues running this, then you need to fetch a newer version of GCC, as this needs C++11 support to compule (see last section for instructuins).

But if all goes to plan, you will get something like this in your terminal:

2015-04-tetris

Use the keyboard to control the game:

Move
Right, down, left
Rotate
Up
Drop
Spacebar
Quit
q

Get a screen

Basically any project with graphics can benefit from one of these. Simply add on a TFT shield, such as PiTFT to create a tiny console:

2015-04-tetris

Of course, this is still keyboard-controlled, but with some hacking, I’m sure you could map touch events to keyboard actions.

Troubleshooting: Update GCC

The Raspbian spftware image which many Raspberry Pi’s have is slightly too old to compile Blocks, which requires C++11 support.

Luckily, it’s very easy to upgrade from wheezy to jessie to add it. You know you need to do this if you get this error compiling:

$ git clone https://github.com/mike42/blocks
$ make
mkdir -p bin
g++ src/main.cpp src/blocks_game.cpp src/blocks_shape.cpp -o bin/blocks -lcurses -lrt -std=c++11 -Wall
cc1plus: error: unrecognized command line option ‘-std=c++11’
cc1plus: error: unrecognized command line option ‘-std=c++11’
cc1plus: error: unrecognized command line option ‘-std=c++11’
Makefile:2: recipe for target 'default' failed
make: *** [default] Error 1

Generally this means you don’t have GCC 4.8, which is not available in wheezy edition of Raspian.

$ g++ --version
g++ (Debian 4.6.3-14+rpi1) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

So to summarise this thread, you need to:

nano /etc/apt/sources.list

Find this line:

deb http://mirrordirector.raspbian.org/raspbian/ wheezy main contrib non-free rpi

And change the word “wheezy” to “jessie”:

deb http://mirrordirector.raspbian.org/raspbian/ jessie main contrib non-free rpi

You can then update everything with:

sudo apt-get update && sudo apt-get dist-upgrade

You are now running the newer jessie release, which gives you access to the GCC 4.8 package we need:

apt-get install g++-4.8

So we can pick up where we left off, and compile the game:

make
./bin/blocks

How to empty your local user account

If you’re not going to use a user account on your computer again, but can’t delete it for some reason, then emptying it is the next best thing to do.

Note: Save anything you want to keep before you start deleting things. These are destructive commands which delete all of the files and settings in the current user’s profile. If you are at all unsure, consider using a file browser to clear out the profile instead.

Windows:

cd %USERPROFILE%
del /A / F /Q /S .

Linux or Mac:

cd ~
rm -Rf .

This will make sure that the disused account no-longer wastes any disk space.

Getting a USB receipt printer working on Linux

In this post, I’ll step through how to get a thermal receipt printer with USB interface appearing on Linux. The aim of this is to be able to point a driver such as escpos-php at the device. The printer used here is an Epson TM-T20, which is very common in point-of-sale environments.

I have previously written quite a bit about how to use thermal receipt printer protocols, but the previous printer I covered had only a network interface, not USB like this one:

2015-03-printer-back
2015-03-printer-top

The directions below are for Debian, but could be adapted for any other Linux.

Find the device file

Plug in your printer, and check that usblp sees it:

dmesg
[12724.994550] usb 8-4: new full-speed USB device number 5 using ohci-pci
[12725.168956] usb 8-4: New USB device found, idVendor=04b8, idProduct=0e03
[12725.168963] usb 8-4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[12725.168968] usb 8-4: Product: TM-T20
[12725.168971] usb 8-4: Manufacturer: EPSON
[12725.168975] usb 8-4: SerialNumber: ....
[12725.175114] usblp 8-4:1.0: usblp1: USB Bidirectional printer dev 5 if 0 alt 0 proto 2 vid 0x04B8 pid 0x0E03

This kernel module makes your printer visible as a device file, so that it can be accessed in the old-fashioned way. Find the new device file under /dev/usb:

ls /dev/usb

In my case, this was /dev/usb/lp1. The next step is to see if you can write to it:

echo "Hello" >> /dev/usb/lp1

Chances are, you will get a permission denied error at this point, so find out what group the printer is in:

stat /dev/usb/lp1

Which will show output something like:

File: ‘/dev/usb/lp1’
  Size: 0         	Blocks: 0          IO Block: 4096   character special file
Device: 5h/5d	Inode: 220997      Links: 1     Device type: b4,1
Access: (0660/crw-rw----)  Uid: (    0/    root)   Gid: (    7/      lp)
...

This file is owned by group lp (“line printer”). If your username was bob, you would add yourself to this group using:

sudo usermod -a -G lp bob

If you plan to build a web-based point-of-sale system with this, then also add the www-data user to that group.

Now log out and back in, and the previous test should now be working:

echo "Hello" >> /dev/usb/lp1

Troubleshooting: Check usblp

If these steps don’t work, then your computer ether doesn’t have, or isn’t using usblp You’ll need to check a few things:

  • Install a different linux-image if the driver is not on your computer at all.
  • modprobe or insmod usblp
  • blacklist a vendor driver which has claimed the interface.
    • run lsusb -v and usb-devices (look for driver=)

Printing something useful

As a duplicated section from my earlier post, the printer uses ESC/POS, which means it accepts plaintext with some special commands for formatting.

A simple receipt-generator, foo.php, might look like this:

<?php
/* ASCII constants */
const ESC = "\x1b";
const GS="\x1d";
const NUL="\x00";

/* Output an example receipt */
echo ESC."@"; // Reset to defaults
echo ESC."E".chr(1); // Bold
echo "FOO CORP Ltd.\n"; // Company
echo ESC."E".chr(0); // Not Bold
echo ESC."d".chr(1); // Blank line
echo "Receipt for whatever\n"; // Print text
echo ESC."d".chr(4); // 4 Blank lines

/* Bar-code at the end */
echo ESC."a".chr(1); // Centered printing
echo GS."k".chr(4)."987654321".NUL; // Print barcode
echo ESC."d".chr(1); // Blank line
echo "987654321\n"; // Print number
echo GS."V\x41".chr(3); // Cut
exit(0);

And you would send it to the printer like this:

php foo.php > /dev/usb/lp1

Scaling this up

The codes are quite tricky to work with manually, which is why I put together the escpos-php driver. You can find it at:

The above example would be written using escpos-php as:

<?php
require __DIR__ . '/autoload.php';
use Mike42\Escpos\Printer;
use Mike42\Escpos\PrintConnectors\FilePrintConnector;
$connector = new FilePrintConnector("/dev/usb/lp1");
$printer = new Printer($connector);

/* Print some bold text */
$printer -> setEmphasis(true);
$printer -> text("FOO CORP Ltd.\n");
$printer -> setEmphasis(false);
$printer -> feed();
$printer -> text("Receipt for whatever\n");
$printer -> feed(4);

/* Bar-code at the end */
$printer -> setJustification(Printer::JUSTIFY_CENTER);
$printer -> barcode("987654321");
$printer -> cut();
?>

This would be sent to the printer by loading it from the web, or running the script on the command-line:

php foo2.php

Configure asterisk with wildcard extensions

This post covers a common use case when deploying a phone system: Somebody in the business needs to be able to record voicemail greetings for other people.

This assumes that you are already running asterisk, and that people already have something in your Dialplan (extensions.conf) for people to record a greeting:

; Record voicemail greeting
exten => *,1,AGI(scripts/record-voicemail-greeting.pl);

To run this script as somebody else, in the phone sense, we just need to change the CallerID before we run it. Some things you’ll need to know to do this:

  1. An “X” in the extension matches any digit
  2. EXTEN is a variable holding the current extension
  3. CALLERID(num) is another variable, which holds the CallerID number
  4. ${EXTEN:2} is a “substring”, which cuts the first two letters off the extension

With that in mind, if * records your own voicmail, then **4567 would record 4567’s voicemail using this snippet:

; Record other person's voicemail greeting
exten => **XXXX,1,Set(CALLERID(num)=${EXTEN:2})
exten => **XXXX,2,Goto(*,1)

Of course, it would be a terrible idea to enable this for the whole business, which is why you can also check the CallerID before you change it. This alternative snippet allows you to record any voicemail greeting, but only if you are calling from 1234.

; Record other person's voicemail greeting (if calling from phone 1234)
exten => 1234/**XXXX,1,Set(CALLERID(num)=${EXTEN:2})
exten => 1234/**XXXX,2,Goto(*,1)

Two ways to back up your Google Apps account

If you use Gmail or hosted Google Apps, you might be interested in taking a backup of your data, such as emails, Drive documents, and calendar entries. Thankfully, you can usually export copy of your account data using Google Takeout.

If your hosted Apps account has Takeout disabled, then you can do a backup, it simply has a few extra steps.

Option 1: Google Takeout

This method is nice and simple. Simply go to the Data tools – Download your data page, and select which services you want to export:

2015-01-google-takeout

It can be a bit eye-opening to see the amount of data Google has on you (Files, conversations, location history, etc). At this point, click through to “Prepare Download”. Depending on the size of your account, this may take as a coffee break, a few hours, or even an entire day.

2015-02-google-takeout-prepare

If you check the box for it, you’ll get an email like this when your Download completes:

2015-02-google-archive

And this lets you fetch a single file:

2015-01-download

The .zip file contains a series of folders, one for each service. The defaults seem to be:

Mail
A unix mbox file
Calendar
One iCal file for each calendar
Contacts
One vCard file for each group.
Drive
Exports as PDF, docx, xlsx

Option 2: Export data from each service

Sometimes, Google Takeout isn’t an option.

2015-01-google-takeout-disabled

Luckily, most Google services have some sort of data export built in. This means, if you have a new contact manager, or want to include your Drive in your PC backup, it’s still possible.

The export formats in these examples should match the Google Takeout defaults. Tab through each service t see how to export it:

If you are not a power user, then I would suggest setting up a copy of Mozilla Thunderbird via IMAP, and regularly using it for your email. This is a simple way to keep a clone of your inbox on your desktop computer, so that it can be included in backups.

If you are more tech-savvy, then the rest of this section will focus on helping you generate an mbox file containing a full backup of your email, the same format as Takeout uses. The best tool for that is a Linux program called getmail.

On Debian or Ubuntu Linux, issue this command to install getmail:

sudo apt-get install getmail4

For other package managers, see these directions.

First, you need to enable IMAP for your account, see Google’s article: Get started with IMAP and POP3, for the steps.

Now create a file at ~/.getmail/getmailrc, and configure it to read your email account via IMAP/SSL.

[retriever]
type = SimpleIMAPSSLRetriever
server = imap.gmail.com
port = 993
username = bob@mail.example.com
password = ....

[destination]
type = Mboxrd
path = ~/inbox

[options]
verbose = 1
getmail

After some time, you will end up with a large mbox file at ~/inbox, containing all of your mail.

If, for some reason, you need to use POP3 instead, then see this article on Gmail backup

Go to your contacts, and find a group. Check the box next to each name, and then find the Export button:

2015-02-contacts-export

Select the vCard format here, as it’s the same format which Takeout would have used:

2015-02-contacts-export-group-vcard

Google provides a share-able iCal link, which you can download once, but it is only available if your calendar is public.

So, if your calendar isn’t too sensitive, click “Share” and make the calendar public:2015-02-calendar-01-share

2015-02-calendar-02-public

Go to “Calendar Settings”, find the iCal link. It may take a few minutes for the link to start working, but once it does, download it, and then turn off public sharing.

There is a small risk that somebody else loads your calendar while its public, so if this concerns you, then save the events individually.

Exporting from Google Drive is nice and simple. Select all of your files (Shift+Click):

2015-02-drive-select

And then find the Download button:

2015-02-drive-download

If you apply this to your whole drive, it may take a while, so you may wish to download it in parts if your Internet can be unreliable.

Know how to export a different service? Send it in and I’ll add it to the list.

How do I use these files?

Google Drive’s files are exported in familiar formats. If you haven’t used an mbox, vCard or ics file before, then you will need to find a program which can read these for you.

Google’s support answer “Download your data: Per-service information” contains a list of files types which you’ll run into during this process, and suggests programs which can import them.

How to merge edges in GraphViz

If you are sketching out a node in graphviz which has many ancestors, a dense collection of arrow-heads can become unsightly:

Example 1 - Edges not merged

The code for the above graph is:

digraph G {
    {a, b, c} -> d;
    d -> e;
}

To merge the edges together, we can instead point these three nodes to an intermediate node, using edges without arrow. This example is adapted from the GraphViz FAQ (link).

This gives us:

Example 2 - edges merged

digraph G {
    d1 [shape=point,width=0.01,height=0.01];
    {a, b, c} -> d1 [dir=none];
    d1 -> d;
    d -> e;
}

To compile these examples, you can use an online tool such as Webgraphviz. If you have GraphViz installed, then run dot over them:

dot -Tpdf example.dot > example.pdf

Howto: Tethered photo capture on Linux

Tethered capture diagram

Have you ever wondered how professionals get photos to pop up on their computer as they snap them? Most higher-end cameras have mini USB connection, and software is available to retrieve images as they are taken.

Rather than use a GUI app, in this post I’ll use a command-line program called gphoto2 to drop the images into a folder. With large thumbnails set in your file browser, a desktop program would be redundant.

First, you need to install the program. Depending on your system, one of the following commands should do the trick:

apt-get install gphoto2
yum install gphoto2

Now, plug in the camera. The command to do a “tethered capture” is:

gphoto2 --capture-tethered

Unfortunately, in most desktop environments, your file manager will mount the camera automatically. If this is the case, then the command will give you an error:

mike@mikebox:~$ gphoto2 --capture-tethered
Waiting for events from camera. Press Ctrl-C to abort.                         

*** Error ***              
An error occurred in the io-library ('Could not claim the USB device'): Could not claim interface 0 (Device or resource busy). Make sure no other program (gvfs-gphoto2-volume-monitor) or kernel module (such as sdc2xx, stv680, spca50x) is using the device and you have read/write access to the device.
*** Error (-53: 'Could not claim the USB device') ***       

For debugging messages, please use the --debug option.
Debugging messages may help finding a solution to your problem.
If you intend to send any error or debug messages to the gphoto
developer mailing list , please run
gphoto2 as follows:

    env LANG=C gphoto2 --debug --debug-logfile=my-logfile.txt --capture-tethered

Please make sure there is sufficient quoting around the arguments.

Simply find the camera and unmount it using the eject button:

Eject the camera storage

Now when you type the command, it will block until a photo is taken, and then show you the name of the photo:

mike@mikebox:~$ gphoto2 --capture-tethered
Waiting for events from camera. Press Ctrl-C to abort.                         
UNKNOWN PTP Property 5007 changed
...
Downloading 'DSC_0236.JPG' from folder '/store_00010001/DCIM/100NCD90'...
Saving file as DSC_0236.JPG                                                    
Deleting 'DSC_0236.JPG' from folder '/store_00010001/DCIM/100NCD90'...

Each of the photos is loaded into the working directory after you release the shutter, so you simply close gphoto2 when you’re done — no manual downloading or SD card required.

Extending this method

Ok, so now that I’ve covered this basic use case, the real reason I suggest gphoto2 is that it will let you script just about anything to do with your camera.

Just typing gphoto2 --help shows that it can let you trigger a photo or video on a timer, download and delete folders from the camera, or hook up programs via a pipe for processing the files in realtime.

Endless possibilities.

Locking down your VOIP setup with a SIP Threat Manager

If you run a Voice over IP network which is available from the Internet, then it’s quite important to lock it down properly, so that it isn’t hijacked for relaying spam calls at your expense.

This article will cover the steps you need to deploy the SIP Threat Manager from Allo, which you can think of as a security-focused SIP proxy & firewall.

Topology

For example, you might have SIP clients both on-site with your server, and also allow people with their own devices to connect directly from home. One of the simplest ways to harden this setup is to add a specialised SIP router between your server and the Internet, to filter connections and log security-relevant events:

VOIP network with STM

VOIP network with STM

This post will show you how to migrate your VOIP network to this more secure topology using Allo’s SIP Threat Manager..

The Allo STM Box

Allo STM front
Allo STM back

The STM itself is only small box, with two 100 Mbit/s Ethernet ports, and two USB ports. It is USB-powered, so one of these ports is for powering the box, and the other is for connecting external storage for log files. It is not power-hungry, and I was able to run it from a laptop USB port without any issues. Other than this, it’s externally a typical embedded network device: it has indicator lights, a power switch, a factory reset button, and a console port.

Allo STM internal

Internally, it runs a MIPS processor, which appears to host Snort on embedded Linux.

Initial Setup

Although the box advertises that it will work out-of-the-box, I found that it was easier to configure the box to match my network, than to re-work my network around the box. This section will simply show you how to get logged in and change the box’s IP address.

First up, I took a look at the console, which is accessible at a baudrate of 38400. It’s far from the most functional CLI around, so I only made use of the factoryreset function to get a clean slate. It showed a few of the open source packages running, such the dropbear sshd, lighttpd and crond among other familiar programs:

Please press Enter to activate this console. 
Starting pid 942, console /dev/ttyS2: '/usr/bin/maincli'
Shield STM Appliance Appliance
shield> factoryreset

Will output 1024 bit rsa secret key to '/etc/dropbear/dropbear_rsa_host_key'
Generating key, this may take a while...
Public key portion is:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgwCKBcVlWK+UiiELbg2CNfOt9rNmj51dmyz7d10MgRfAk9XU9x+kmlMueCFEBMTchsaywigLw0yFqeMZ
Fingerprint: md5 50:5b:c2:64:d4:87:f8:86:ab:c6:e1:59:e4:16:c2:cf
Generating a 1024 bit RSA private key
...++++++
...................++++++
writing new private key to '/etc/lighttpd/webserver.pem'
-----
ip: RTNETLINK answers: No such process
Jan  1 00:40:41 crond[875]: crond 2.3.2 dillon, started, log level 8

mount: mounting /dev/sda1 on /cf/disk failed

The CLI command show ip confirmed that the default IP of the box is 192.168.100.1, netmask 255.255.255.0. From a Linux laptop, you can change IP to something nearby and confirm that you can see the device with these commands:

# ifconfig wlan0 192.168.100.2 netmask 255.255.255.0
# arp-scan -l
Interface: wlan0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.8.1 with 256 hosts (http://www.nta-monitor.com/tools/arp-scan/)
192.168.100.1	00:17:f7:00:9b:0a	CEM Solutions Pvt Ltd

The STM is then accessible via the web address https://192.168.100.1, with the default credentials admin / admin.

STM login

The IP setup is located under Device → General Setup. Change this to DHCP or a spare address on your network:

STM IP config

Configuration

Now that you can access the STM from any device, your first task is to change the admin password. The button for this is in the top-right:

2015-01-stm-screen21

The STM only allows one session at a time- whilst it’s a good idea not to log in twice, this was a surprising limitation. At the STM does not act as its own SIP endpoint, my server was already able to contact the Internet through it at this point.

I quickly screen captured the available settings so that you can click through them. Some of these are SIP-specific, and others of which are general firewall features. One of the more interesting features which you can’t set up with iptables is location-based IP filtering. This could, for example, block problematic SIP calls coming from fraud hotspots in areas where your organisation doesn’t operate.

So once the network is set up on the STM, no changes need to be applied to your SIP server, other than its gateway or IP.

Notes

Whilst this box works as it’s supposed to, I found it to have an un-polished user experience.

  • The network interface labels on the box had a label over them with the opposite information.
  • The box is closed on port 80: It doesn’t reply to HTTP requests, even to redirect them to HTTPS.
  • The command prompt wasn’t as useful as other network devices.
  • I couldn’t get SSH login or NTP to work, although I didn’t investigate these in great detail.
  • The LAN interface (but not the WAN interface) did not light up when connected to a Gigabit POE network, but did work on a 100 megabit network.

However, there are some positives: The 100 Mbit/s interfaces are more than sufficient for voice traffic, the configuration was simple, and USB is a good choice of power supply for equipment which can be connected directly to a server.

Do you really need another box?

This depends on your setup. If your VOIP server doesn’t speak to the Internet, then this box wont fit into your topology.

If it only sees the outside world via an ISP-run SIP trunk, then this type of security is probably not necessary either. Security measures you would use instead are:

  • Use firewall rules to restrict connections so that only the SIP trunk can speak to your VOIP server.
  • Configure your VOIP server to “stay on the line” for calls (directmedia=no in Asterisk) so that the phones do not speak directly to the trunk, and disallow registration from the Internet.

If your VOIP server accepts connections from the public internet throgh SIP, then some sort of separate, SIP-aware firewall or proxy is highly advisable.

Acknowledgement

Thanks to Allo (allo.com) for sending in the box which is used for this example setup.

How to set up Asterisk in 10 minutes

Asterisk is an open-source IP PABX, meaning it lets you run a phone system over your computer network. Whilst IP telephony has been gaining the upper hand over traditional PABX’s for years, few people outside the industry realise just how easy it is to set up your own phone server.

With this guide, you can turn any Linux device into your own PABX for free. We’ll set up two SIP devices on a small network, so that they can dial each other.

Diagram showing how the two example users will connect to the server

Prepare the environment

First, you should get something with Linux. A virtual machine, a spare laptop, a Raspberry pi- anything.

Install asterisk with one of the following commands, depending on your distribution:

apt-get install asterisk
yum install asterisk

If you don’t have an IP phone handy, then you need a program on your computer which speaks SIP (Session Initiation Protocol). This guide uses Linphone (available for Linux and Windows among other platforms) and the Polycom 331 as examples, but any two SIP endpoints will work just as well for testing.

Make users on the server

Asterisk keeps its configuration in /etc/asterisk. The file we need to edit for this setup is users.conf. Open it up with your favourite text editor:

nano /etc/asterisk/users.conf

The syntax is similar to .ini files. Add two users to the bottom of the file:

[6001]
fullname = Example Bob
secret = 1234
hassip = yes
context = users
host = dynamic

[6002]
fullname = Example Joe
secret = 1234
hassip = yes
context = users
host = dynamic

What does this mean?

[600..]
This is the username, and will become the user’s extension on our small network. Dial 6001 for Bob or 6002 for Joe. Whilst 'bob' and 'joe' could also be used here, numeric usernames are more common.
fullname = ...
Used in the Caller ID.
secret = ...
The password used to log in. In a secure system, you would use something other than 1234!
hassip = yes
This tells Asterisk to make a SIP account for the user. Asterisk supports a few other account types, but SIP is the most widely implemented.
context = users
A context is a bit like a category for the user. The extensions which they can dial depend on this.
host = dynamic
This tells Asterisk that the users don’t have a fixed IP address. This means that they must register periodically with the SIP server so that their IP is known.

To activate these changes, save the file, and reload the configuration through the Asterisk console:

mike# asterisk -r -vvvvvvvvv
CLI> reload
CLI> sip show users
Username                   Secret           Accountcode      Def.Context      ACL  ForcerPort
6002                       1234                              users            No   Yes       
6001                       1234                              users            No   Yes       

All of those v‘s stand for verbose, meaning that the asterisk console will give you more information.

Configure the clients

First you should find out your server’s IP address. From the terminal, you can find this with:

ifconfig

Setting up “Example Joe” on a Linphone instance only takes a few clicks. Add a new account, with 6002 as the identity, and your asterisk server as the proxy address (eg: sip://voip.example.com). Click the image below for an example:

Linphone account setup

Linphone account setup

Meanwhile, the Polycom 331 can be configured as “Example Bob” by navigating the menus on the phone itself, or via the web (suggested). The default login is:

Username:
Polycom
Password:
456
Polycom 331 configuration page

The Polycom 331 web interface.

Your asterisk server address needs to be added under SIP -> Servers -> Server 1, while Example Bob’s identity is added under Lines -> Line1. Click the below images for an example.

Polycom 331 configuration page
Polycom 331 configuration page

Server (SIP) configuration on the left, and line configuration on the right.

Once these are saved, the two clients will register with the server. In SIP, clients periodically register so that the server knows where to find them.

In the asterisk console, you will see something like this:

-- Registered SIP '6001' at 192.168.1.4:5060
   > Saved useragent "PolycomSoundPointIP-SPIP_331-UA/3.3.3.0069" for peer 6001

If registration fails, the console will tell you why, provided that you have set the verbosity high enough

You can check which users have registered with this command:

CLI> sip show peers
Name/username              Host                                    Dyn Forcerport ACL Port     Status     
6001/6001                  192.168.1.4                              D   N             5060     Unmonitored 
6002                       (Unspecified)                            D   N             0        Unmonitored 
2 sip peers [Monitored: 0 online, 0 offline Unmonitored: 1 online, 1 offline]

Unfortunately, even after both users have registered, they aren’t ready to communicate yet.

Add extensions to the server

In the world of VOIP, an extension is not a real loop of copper, but a sequential list of things to do when a number is dialled.

This extra step is where Asterisk gets its flexibility. With your extensions.conf setup, you could set your instance to redirect numbers, or dial for 12 seconds before going to voicemail.

We haven’t told the server what to do, so if “Example Bob” makes a call, it wont work yet:

  == Using SIP RTP CoS mark 5
[Nov 15 07:59:30] NOTICE[6070]: chan_sip.c:22753 handle_request_invite: Call from '6001' (192.168.1.4:5060) to extension '6002' rejected because extension not found in context 'users'.

To add extensions, open extensions.conf up:

nano /etc/asterisk/extensions.conf

The syntax is still INI-like. Under [users], we add the steps for each extension, numbered sequentially. In this case, there is only 1 step for each extension: to dial a SIP user.

[users]
exten => 6001,1,Dial(SIP/6001)
exten => 6002,1,Dial(SIP/6002)

In the Asterisk console, type reload to activate the changes.

Now, as planned, both users on the network can dial each-other and have a chat.

More advanced setups

Ok, time to do a reality check. You’ve built an intercom, but not a full phone system! For a start, you need a way to dial the outside world, and let the outside world dial you. For this, you’ll need to work with hardware and service providers.