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.bizfrom 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.bizimport 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