Introduction: Controlling a Kwikset Smartcode Lock With an Intel Edison

In this Instructable we'll show you how to control a Kwikset ZigBee lock with Intel Edison.

Note: The original work for this Instructable was done during the Intel IoT Roadshow Hackaton on 3/14/15.

For our setup we used this lock from Kwikset that normally communicates with a home automation hub using ZigBee. We begin by going over the serial interface to our lock and then we'll show you how to implement that interface using Python.

For this Instructable you'll need:

- Kwikset Smartcode ZigBee Deadbolt

- Intel Edison

- Arduino breakout board for the Intel Edison

- Three male jumper wires

- (optional) 9V battery

Step 1: Prepare Your Edison

I'm going to assume that you have the latest firmware on your Edison and that you can run Python scripts on your Edison.

From there you'll want to connect to your Edison through the serial terminal or through an SSH connection.

Once you're in your Edison make a directory for your python scripts.

mkdir kwsedison

This is the directory you'll be working from.

Step 2: Add Kwikset Protocol Script

Now open up a new document and name it kwikset_protocol.py using the following command

vi kwikset_protocol.py

In this case I've used vi, but you can always install and use nano or any other text editor of your choice.

This is the script that will contain all the commands for communicating with your Kwikset lock over UART.

Paste the following code into your file, save your file, then exit your text editor.

#!/usr/bin/python

# This is a library for providing access to Kwikset Smartcode Locks via UART # The h/w interface is 3.3V 9600 baud 8N1 standard UART # This is more of a protocol encoder/decoder though
# You can find more information at randomwire.biz

from binascii import hexlify,unhexlify

pkt_count = 0

NO_DATA = '' LOCK_CMD = 'e703' UNLOCK_CMD = 'e705' INIT_CMDS = ('e707','e74d','e702','e70a','e718','e709','e742','e70f') INIT_DATAS = ('','','','','','','01010101','15031301471205') PARSE_LOOKUP = {'e709':"parse_initack",'e727':"parse_lockstatus",'e729':"parse_newlockcode",'e742':"parse_error"}

def generate_packet(cmd,data): global pkt_count pkt_count += 1 length = (len(cmd+data)/2)+2 base_pkt = "%0.2x%0.2x" % (length,pkt_count)+cmd+data pkt = "bd"+base_pkt+calculate_crc(base_pkt) return pkt

def calculate_crc(pkt): crc = int("ff",16) #print "Starting crc = %0.2x"%crc while len(pkt)>1: crc ^= int(pkt[0:2],16) #print "After byte 0x%s, CRC = %0.2x, Len=%d"%(pkt[0:2],crc,len(pkt)) pkt = pkt[2:] return "%0.2x"%crc

def validate_crc(pkt): if calculate_crc(pkt) == '00': return True else: return False

def parse_packet(pkt): if pkt[0:2] != 'bd': print "Bad packet header" return False if not validate_crc(pkt[2:]): print "Bad packet CRC" return False if ((len(pkt)/2)-2) != int(pkt[2:4],16): print "Bad packet length" return False cmd = pkt[6:10] data = pkt[10:-2] print "Found cmd=%s & data=%s"%(cmd,data) if cmd in PARSE_LOOKUP: parse = globals()[PARSE_LOOKUP[cmd]] return parse(data) return True

def parse_initack(data): if data == '64': return True else: return False

def parse_lockstatus(data): code_used = int(data[2:4],16) status_bits = int(data[4:6],16) if status_bits & 0x80: cause = "Remote Control" elif status_bits & 0x40: cause = "Code %d Entered"%(code_used) elif status_bits & 0x20: cause = "Automatic Lock" else: cause = "Manual/Key" if status_bits & 0x02: lock_state = "Unlocked" elif status_bits & 0x01: lock_state = "Locked" else: lock_state = "Unknown" return (lock_state,cause)

def parse_newlockcode(data): return data

def parse_error(data): return data

def generate_init_packet(num): return unhexlify(generate_packet(INIT_CMDS[num],INIT_DATAS[num]))

def generate_lock_packet(): return unhexlify(generate_packet(LOCK_CMD,''))

def generate_unlock_packet(): return unhexlify(generate_packet(UNLOCK_CMD,''))

Step 3: Add Kwikset Control Script

With your protocol script done you can now add your control script.

Create another python script called kwikset.py

vi kwikset.py

This python script will be the kwikset library you can call to lock and unlock your deadbolt.

Paste the following code into your text editor, save, then exit your text editor.

#!/usr/bin/python

# This is a library for providing access to Kwikset Smartcode Locks via UART # The h/w interface is 3.3V 9600 baud 8N1 standard UART # This is more of a protocol encoder/decoder though
# You can find more information at randomwire.biz

import kwikset_protocol import serial import time import os import threading from binascii import hexlify,unhexlify

ser = None

def setup_arduinobreakout_pins(): # First let's make sure all the pins are exported for config os.system("echo 214 > /sys/class/gpio/export") os.system("echo 248 > /sys/class/gpio/export") os.system("echo 249 > /sys/class/gpio/export") os.system("echo 216 > /sys/class/gpio/export") os.system("echo 217 > /sys/class/gpio/export") # Shouldn't need this as serial port opening should take care of it #os.system("echo 130 > /sys/class/gpio/export") #os.system("echo 131 > /sys/class/gpio/export") # Next lets Tristate all the outputs os.system("echo low > /sys/class/gpio/gpio214/direction") # Next lets setup the buffer/level shifter I/O directions os.system("echo low > /sys/class/gpio/gpio248/direction") os.system("echo high > /sys/class/gpio/gpio249/direction") # Disable the external pull ups os.system("echo low > /sys/class/gpio/gpio216/direction") os.system("echo low > /sys/class/gpio/gpio217/direction") # Set Edison I/O directions (shouldn't be necessary, but here for posterity #os.system("echo in > /sys/class/gpio/gpio130/direction") #os.system("echo out > /sys/class/gpio/gpio131/direction") # Remove tristate os.system("echo high > /sys/class/gpio/gpio214/direction") def setup_serial(): global ser # Initialize serial port ser = serial.Serial("/dev/ttyMFD1",9600,timeout=0) def unlock(): global ser if ser == None: print "Serial Port not setup" return False ser.write(kwikset_protocol.generate_unlock_packet()) def lock(): global ser if ser == None: print "Serial Port not setup" return False ser.write(kwikset_protocol.generate_lock_packet())

Step 4: Wire Up Your Edison to Your Kwikset Lock

On the inside of your Kwikset lock you should see a green printed circuit board with a ZigBee board plugged into it.

Remove the ZigBee board and wire according to the picture.

Using your jumpers connect ground to ground, TXD from your lock to 1RX on your Edison, and RXD from your lock to 1TX on your Edison.

These are all the connections you'll need to make to control your Kwikset lock from the Edison.

Optionally, you can power your Edison from a 9V battery. We found that with WiFi on, a standard 9V battery lasts about an hour.

Step 5: Test It Out!

With all your scripts in place and your hardware all setup--you're now ready to test your Edison controlled lock.

Start by going into your kwsedison directory if you're not already there. We're going to run our test in Python so just enter the following command into your terminal.

python

Now import your kwikset.py script

import kwikset.py

To begin we need to initialize our serial connection and setup our pins for the Arduino breakout board

kwikset.setup_serial()
kwikset.setup_arduinobreakout_pins()

You only need to initialize your serial connection and Arduino pins once before using the lock and unlock commands.

To unlock your lock run

kwikset.unlock()

To lock your lock run

kwikset.lock()

If everything worked as it should your lock and unlock commands should be unlocking and locking your Kwikset lock!

Step 6: Next Steps and More Information

Next Steps

In a future instructable I'll go over how we connected our Edison to the Internet using Autobahn and Crossbar.io.

More Info

You can find all the code I've used in this Instructable on our Github repository:

https://github.com/RandomWireTechnologies/Keyforal...

To get in touch with us you can find our contact info on https://randomwire.biz