Thursday 14 January 2016

Controlling my Electronic Door Lock using an Arduino


This post is part 2 in a 3 part series that shows how I hacked an off-the-shelf electronic lock to be controlled by my Android phone using a Bluetooth capable Arduino board.  

Ostensibly to prevent my cute children from raiding my home office, but more likely because I think it's cool.

In the last post, I used a small digital oscilloscope (Bitscope) and an Arduino compatible board (Bluno Beetle) to figure out the protocol that the two halves of my electronic doorlock use to communicate.

So, now that I know the protocol to the electronic door lock, I can hack it!  So the first thing I did was wire up TX pin on my Bluno Beetle board (the Arduino compatible board with BT-LE) to the TX line from the keypad, the RX pin to the RX line to the keypad, and Vin to +6 VDC from the battery [1]. 



Before continuing, a few things to consider.  I'm tapping the wires going between the two halves of the door lock, but electrically this may not be the greatest idea:
  • I have no idea how much current either half will source or sink, so this may not work at all.  We *hope* that the inputs are high impedance, and that that outputs don't source too much current.
  • The TX line from the keypad is normally high, so we're actually pulling the voltage down on the TX line down whenever we send data.  
  • The RX line from the keypad isn't an issue, since Arduino pins configured as inputs have very high impedance.
  • I'm trying to wire it up this way anyway since I don't want the Bluno board to sit between the two halves of the door lock.
That being said, here's the source to control the doorlock:

#include <SoftwareSerial.h>

SoftwareSerial doorSerial(2, 4); // RX, TX

void setup() {
    // initialize the real (UART) Serial
    Serial.begin(115200);
    // initialize the SoftwareSerial port
    doorSerial.begin(9600);
    // Put TX in a high impedance state when not sending
    pinMode(4, INPUT);
}

void writeDoorCommand(uint8_t command) {
    pinMode(4, OUTPUT);
    digitalWrite(4, 0);
    delay(30);
    digitalWrite(4, 1);
    delayMicroseconds(1200);
    doorSerial.write((uint8_t)command);
    pinMode(4, INPUT);
}

void loop() {
    if (doorSerial.available()) {
        Serial.print("0x");
        // send what has been received
        Serial.println(doorSerial.read(), HEX);
    }
    if (Serial.available()) {
        // send what has been received
        writeDoorCommand(Serial.read());
    }
    // Add a delay to avoid characters being sent too quickly to the door lock
    delay(100);
}


I'm using the timing information that I figured out in part 1 of this series.

You'll also notice that I actually switch the TX pin to high impedance (input mode) when not actively sending data.  This way it won't source or sink any current when it doesn't have to, or interfere with the normal communications between the two halves of the door lock.

Now to test it!  Fortunately, the DF Robot guys provided some Android code for sending and receiving characters via Bluetooth to and from the Bluno Beetle, so I don't need to do this over USB serial.

I took the simple sample code they provided [here], and modified it to send commands to the electronic door lock [modified version here].  And guess what, it works!  I can now remotely enter the code from my Android device, and unlock the door.



The next small change I made was to make the Arduino code more power friendly, by going into sleep mode when not sending or receiving data.  I found the following page pretty useful:

http://playground.arduino.cc/Learning/ArduinoSleepCode

Using this information, I modified the code to the following:


#include <SoftwareSerial.h>
#include <avr/power.h>
#include <avr/sleep.h>

SoftwareSerial doorSerial(2, 4); // RX, TX

void setup() {
    // initialiaze the real (UART) Serial
    Serial.begin(115200);
    // initialize the SoftwareSerial port
    doorSerial.begin(9600);
    // Put TX in a high impedance state when not sending    
    pinMode(4, INPUT);
}

void writeDoorCommand(uint8_t command) {
    pinMode(4, OUTPUT);
    digitalWrite(4, 0);
    delay(30);
    digitalWrite(4, 1);
    delayMicroseconds(1200);
    doorSerial.write((uint8_t)command);
    pinMode(4, INPUT);
}

// Put the device into sleep mode
void sleep() {
    set_sleep_mode(SLEEP_MODE_IDLE);
    
    // Set Power Reduction register to disable timer (used by SoftSerial)
    PRR = PRR | 0b00100000;
    
    power_adc_disable();
    power_spi_disable();
    power_timer0_disable();
    power_timer1_disable();
    power_timer2_disable();
    power_twi_disable();

    // Enter sleep mode
    sleep_enable();
    sleep_mode();
    
    // Return from sleep
    sleep_disable();
    
    // Re-enable timer
    PRR = PRR & 0b00000000;
    
    power_all_enable();
}

void loop() {
    bool canSleep = true;
    while (doorSerial.available()) {
        canSleep = false;
        // send what has been received
        Serial.print("0x");
        Serial.println(doorSerial.read(), HEX); 
    }
    while (Serial.available()) {
        canSleep = false;
        // send what has been received
        writeDoorCommand(Serial.read());
    }
    
    // Sleep if there is no activity on the serial port
    if (canSleep) sleep();
    
    // Add a delay to avoid characters being sent too quickly to the door lock
    delay(100);
}

Data from either the door or the Bluetooth module will now wake the Arduino module from sleep mode, so that it's not constantly consuming full power [2].

Now that I've got something that works, I'll put the whole thing into a project box to make it look like I know what I'm doing.  Here are the before and after pictures:

Before After

Ok, so that's great, but this Android app is really just cut and copied example code, and doesn't add much in the way of convenience.  In the next part, I'll going to describe how to write a better app.  The app I actually want to use everyday.

[1] Unfortunately the Bluno Beetle does not run on 3.3v, otherwise I could power it from the door lock's 3.3v wire.  The Bluno Beetle really should use a 3.3v ATMega chip, since the BT module requires 3.3v anyway which the Bluno Beetle produces using a voltage regulator located on the PCB.  This conversion to 3.3v (not to mention from 6v to 5v) wastes a lot of power in the form of heat.


[2] Another unfortunate issue is that although the ATMega chip can be put into low power mode, the firmware for BT radio doesn't yet support this.  So we can only reduce the power consumption to a certain point, since the BT radio is still drawing full power.


See part 3 of My Fancy Bluetooth-LE Operated Door Lock series:

Controlling my Electronic Door Lock from Android using Bluetooth-LE (coming soon...)

3 comments :

  1. this would also be very useful for the Alzheimer's society who have patients who are at risk of wondering in to the basement our outdoors

    ReplyDelete
  2. Is there a better chipset that will put BLE to sleep to reduce power consumption?

    ReplyDelete