How To: Integrate Your Home Phone with OpenHAB

Do you still own a home phone? I do! It came with my cable and Internet service as a bundle. This tutorial will show you how to integrate your home phone with OpenHAB.

Get an Orange Pi Zero ($9!!!)

I used an orange pi zero mainly because of the built-in ethernet. Though its bandwidth is shared amongst the USB hub, it’s more than adequate for this purpose.

Install Armbian

Perhaps any other ARM-based OS of your choice!
At the time of this tutorial, I used the headless Armbian_5.35_Orangepizero_Ubuntu_xenial_default_3.4.113

Get a USB Modem

We need to have a way to connect the Pi to the phone jack. A USB dial-up modem should suffice.

  1. Plug in

  2. Check using lsusb/dmesg

    lucky@callerid:~$ lsusb
    ...
    Bus 006 Device 003: ID 0572:1340 Conexant Systems (Rockwell), Inc.
    
    lucky@callerid:~$ sudo dmesg | grep USB
    ...
    [ 1222.944998] cdc_acm 6-1:1.0: ttyACM0: USB ACM device
    [ 1222.981669] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
    ...
    

    Important: make note of: dc_acm 6-1:1.0: ttyACM0: USB ACM device

    Good! Pi recognized the device without any extra drivers needed.

Get a Phone Jack (RJ11) splitter

If you have a spare phone jack in your home, then you won’t need this.

Configure your Orange Pi

  • sudo armbian-config

I often change the timezone and locale settings, as well as the hostname of the device.

Optional: Add the MAC ID to your DHCP server to manually set the route.

Installation

  1. Update then upgrade
    1. sudo apt-get update
    2. sudo apt-get upgrade
      • This will take a while.
      • Take a coffee break.
  2. Install required packages and tools
    1. sudo apt-get install libpcap0.8-dev
    2. sudo apt-get install build-essential
    3. sudo apt-get install gdebi
  3. Get and install the package
    1. wget http://cfhcable.dl.sourceforge.net/project/ncid/ncid/1.7/ncid_1.7-3_armhf.deb
    2. sudo gdebi ncid_1.7-3_armhf.deb
  4. Configure
    1. Edit configuration file
      1. sudo nano /etc/ncid/nicdd.conf
        • set ttyport = /dev/ttyACM0
          This is from your dmesg command above
    2. Start the service
      1. sudo service ncidd start

Initial Testing

  1. Telnet to your orange pi IP using port 3333…

  2. Call the phone number the phone jack is connected to. You should see your own phone number and this output in telnet:

     200 Server: ncidd (NCID) 1.7
     210 API: 1.6 Feature Set 1 2 3 4 5
     252 Call log empty
     OPT: LineIDS: POTS
     300 End of connection startup
     CIDINFO: *LINE*POTS*RING*1*TIME*23:21:34*
     CID: *DATE*02062018*TIME*2321*LINE*POTS*NMBR*XXXXXXXXXX*MESG*NONE*NAME*MALLARI LUCKY*
     CIDINFO: *LINE*POTS*RING*0*TIME*23:21:46*
     

    It works! You should see your phone number instead of the XXXXXXXXXX. As you can see, it shows my name also (this will be the caller’s name).

Notes

  • NCID is very lightweight. You can install this alongside your OpenHABian

OpenHAB Integration

  1. Create (and verify) a backup of your OpenHAB

  2. Install TCP Binding

  3. Install REGEX Transformation

  4. Configure your item (change IP and PORT)

    String callerid_raw    "[%s]" { tcp=">[192.168.1.166:3333:'REGEX((.*))']" } 
    DateTime callerid_time "[%s]" 
    String callerid_phone  "[%s]" 
    String callerid_name   "[%s]" 
    String callerid_message "[%s]" 
        ```
    
  5. Add your rule

    /* 
    	Items:
    	String callerid_raw
    	DateTime callerid_time
    	String callerid_phone
    	String callerid_name   
    	String callerid_message
    */
    
    import java.text.DateFormat
    import java.text.SimpleDateFormat
    import java.util.Date
    
    rule "Caller ID"
    when 
    	Item callerid_raw changed
    then
    	var raw = callerid_raw.state.toString
    	logInfo("CallerID", "..parsing")
    	if (raw.contains("CID:")) {
    		//CID: *DATE*02062018*TIME*2321*LINE*POTS*NMBR*XXXXXXXXXX*MESG*NONE*NAME*SMITH JOHN*
    		var parts = raw.split("\\*")
    		var callerDateTimeString = parts.get(2) + parts.get(4)
    		val callerNumberRaw = parts.get(8)
    		var callerMessage = parts.get(10)
    		var callerName = parts.get(12)
    		
    		if (callerMessage == "NONE")
    			callerMessage = ""
    		
    		val String callerNumber = callerNumberRaw.substring(0, 3) + "-" + callerNumberRaw.substring(3,6) + "-" + callerNumberRaw.substring(6) 
    		
    		var DateFormat format = new SimpleDateFormat("MMddyyyyHHmm");
    		var Date callerDateTime = now
    		
    		try {
    			callerDateTime = format.parse(callerDateTimeString);
    		} 
    		catch(Throwable t) {
    			logError("CallerID", "Unable to parse date: " + callerDateTimeString)
    		}
    		val String toHabPanelVoice = "Call from " + callerName + " (" + callerNumber + ") on " + new SimpleDateFormat("hh:mm a").format(callerDateTime) + " {" + callerMessage + "}"
    		sendCommand(hp_s_voicer, toHabPanelVoice)
    		sendCommand(hp_s_activateDashboard, "Caller ID")
    		sendCommand(callerid_time, DateTimeType.valueOf(new SimpleDateFormat(DateTimeType.DATE_PATTERN).format(callerDateTime)))
    		sendCommand(callerid_phone, callerNumber)
    		sendCommand(callerid_name, callerName)
    		sendCommand(callerid_message, callerMessage)
    	}
    end
    

    Note this:

    val String toHabPanelVoice = "Call from " + callerName + " (" + callerNumber + ") on " + new SimpleDateFormat("hh:mm a").format(callerDateTime) + " {" + callerMessage + "}"
    sendCommand(hp_s_voicer, toHabPanelVoice)
    sendCommand(hp_s_activateDashboard, "Caller ID")
    

    That’s for my HABPanel. It will:

    • Say “call from …”
    • Switch to this dashboard:

HABPanel Template Widget

<style>
  .callerid {
  	font-size: 16px;
  	text-align: center;
  }
	.callerid h1, h2 { 
    margin: 0;
    position: relative;
    width: auto;
	}
  .callerid h1 {
   	font-size: 10em;
  	color: darkkhaki;
  	animation: blinker 1s linear infinite;
  }
  .callerid h2 {
   	font-size: 7em
  }
  .callerid div {
   	font-size: 4em
  }

  @keyframes blinker {  
	  50% { opacity: 0; }
	}
</style>
<div class="callerid">
	<h1>Phone Call!</h1>
	<h2>{{itemValue('callerid_name')}}</h2>  
	<div><em>{{itemValue('callerid_time') | date: 'M/dd/yy HH:mm a'}}</em></div>
	<div>{{itemValue('callerid_phone')}}</div>
	<div>{{itemValue('callerid_message')}}</div>
</div>

What’s Next (TO-DO)

I’ll show you how to turn this as a

  • Screener (blacklist calls based on phone numbers/marketers)
  • Answer calls
  • Make phone calls (good for a Panic! button by dialing 911)
  • Send a fax
4 Likes

.Todo.

Very nice. A lot lighter weight than setting up Asterisk or FreeSwitch. Very clear tutorial. Thanks for posting!

Hi Lucky,

Great tutorial, thanks I have just set it up and I love it.

I have changed the rule code to use the items methods instead of the actions:

		sendCommand(hp_s_voicer, toHabPanelVoice)
		sendCommand(hp_s_activateDashboard, "Caller ID")
		sendCommand(callerid_time, DateTimeType.valueOf(new SimpleDateFormat(DateTimeType.DATE_PATTERN).format(callerDateTime)))
		sendCommand(callerid_phone, callerNumber)
		sendCommand(callerid_name, callerName)
		sendCommand(callerid_message, callerMessage)

to:

		hp_s_voicer.sendCommand(toHabPanelVoice)
		hp_s_activateDashboard.sendCommand("Caller ID")
		callerid_time.sendCommand(DateTimeType.valueOf(new SimpleDateFormat(DateTimeType.DATE_PATTERN).format(callerDateTime)))
		callerid_phone.sendCommand(callerNumber)
		callerid_name.sendCommand(callerName)
		callerid_message.sendCommand(callerMessage)

Regards

1 Like

Nice!

I also want to point out to everyone that if you’re not using HABPanel, you can use your favorite audio sink and use the say command in OH

That’s what I was planning to do!!
And also pause the TV if certain people call… neat

I have noticed something else, the location of the ncidd.conf file is not /etc/ncidd.conf but /etc/ncid/nicdd.conf

Thanks

…or chain it with this to show a caller id on the TV. Fortunately my phone and cable TV provider (Xfinity) provides this feature already with their set top boxes.

You can also count the number of rings in OH, and after a certain number of rings, send a text message to your phone for the missed call.

Fixed. Thanks!

Hi Lucky,
After a bit of trying to make it work the following need to be done
In the tcp.cfg file, the port and refreshinterval line must be uncommented to allow receiving of data

1 Like

Yeah, I’ll add that also.

I have just got this working great in openhab3 with the USRobotics 5637. There is currently no TCP binding in OH3, so used the Logviewer binding. Code below:

phone.things
logreader:reader:phoneLog [
filePath="/var/log/cidcall.log",
customPatterns="CID: "
]

phone.items
String PhoneRaw “Phone Log [%s]” { channel=“logreader:reader:phoneLog:lastCustomEvent” }
DateTime PhoneTime “Phone Time [%1$td/%1$tm/%1$ty %1$tH:%1$tM]”
String PhoneNumber “Phone Number [%s]”
String PhoneName “Phone Name [%s]”
String PhoneMessage “Phone Message [%s]”

phone.rules
rule “Caller ID”
when
Item PhoneRaw received update
then
var parts = PhoneRaw.state.toString.split("\*")
if (parts.get(12) == “NO NAME”) parts.set(12,"")
if (parts.get(10) == “NONE”) parts.set(10,"")
PhoneNumber.postUpdate(parts.get(8))
PhoneName.postUpdate(parts.get(12))
PhoneMessage.postUpdate(parts.get(10))
PhoneTime.postUpdate(now.toLocalDateTime().toString())
end

1 Like