Posted by & filed under Android, Python, RaspberryPi.

Disclaimer: This will most likely void your Mighty Mule warranty! Read this write-up below in its entirety before proceeding. We are not liable for any harm you cause to yourself or property damaged as a result of attempting this. Electricity is extremely dangerous and can cause serious injury and death. Use the information below at your own risk and consult a certified electrician before attempting any electrical work.

At our home we have a Mighty Mule FM350 Gate Opener that operates an 8′ gate to keep our driveway secure and our Boxer mix contained. Mighty Mule packaged the FM350 with a couple RF transmitters that tend to stay permanently affixed to our vehicle’s sun visors. Getting to just the point on the other side of the gate means walking almost a complete circle around the house (through a smaller, non-automatic gate on the opposite side).

dendron

 

I thought it would be a good exercise in ingenuity to build a simple Android widget for my Moto X that opened the gate via Bluetooth. Since the gate opener requires a 12v battery to operate (drip charged via a wire that runs under the house), I had easy access to power, even during a power outage.

Parts list

  • Mighty Mule FM350 12v Gate Opener (requires 12v car/truck battery)
  • RaspberryPi B+ (and a TV/Monitor with HDMI support, USB keyboard, HDMI cable for initial setup)
  • RaspberryPi B+ compatible power supply (microUSB phone charger usually suffices)
  • Autek 12v to 5v DC Converter
  • Edimax USB WiFi Dongle (optional)
  • Sabrent Micro Bluetooth Adapter
  • SainSmart 2-channel 5v Relay
  • Solderless breadboard for prototyping
  • Adafruit Pi Cobbler or similar for prototyping
  • Solderable board to hold your components after prototyping (I used this)
  • Various male-to-male breadboard wires for prototyping
  • Various male-to-female wires for making connections to pins
  • 1 x 2N2222 transistor
  • 1 x 10k ohm resistor
  • 2 x 360 ohm resistors or 4 x 180 ohm resistors
  • Battery terminal connectors for the DC converter
  • Voltmeter
  • Some way to waterproof your circuitry (I 3D printed an enclosure and placed it in my 12v battery box)

In addition to its own RF transmitters, the FM350 supports a suite of other options such as keypad entry, push button switches, motion sensors, etc. Opening the gate opener case and exposing the circuit board provides very easy access to several input connections (see page 32 of FM350 Manual for a description of each terminal). We’re going to be working with the COMMON and CYCLE terminals.

IMPORTANT: ** DO NOT ** supply any external voltage to the terminals!

The input terminals are only designed to support the low voltage provided by the COMMON terminal and no more. Failure keep voltage away from the terminals could result in burning out the circuitry and destroying your gate opener.

Our goal is to provide a switchable way to bridge the COMMON and CYCLE terminals which triggers the gate to open or close. You can test this by placing a wire between the COMMON and CYCLE terminals for a second or two and the gate opener should activate. Bridging the two terminals again will stop the opener if it hasn’t finished its cycle and one last time will activate the closing action. This same method is what’s used by wired push button and keypad openers, so it should be reliable.

Choosing a switch

Since we need to be very careful about inadvertently energizing the input terminals with any voltage other than what the COMMON terminal provides, I opted to isolate the circuit with a relay. I chose the mechanical SainSmart 2-channel 5v relay. It’s possible a solid state relay would be safer, but I wanted to stay as inexpensive as I could manage and the 5v supply would play nicely with the RaspberryPi. Do note that during construction of the circuit I realized that this relay operates backwards to what I would’ve expected, activating when the input was LOW and deactivating when HIGH. That made things more complicated, but also made for a brain exercise.

RaspberryPi Initial Setup

If you don’t already have Raspbian installed on an SD card, head over to the downloads section of raspberrypi.org, download an image, and follow the instructions for installing onto your SD card. This can take a while, so start it now. Continue reading while you wait.

RaspberryPi Configuration: WiFi

After Raspian is installed, plug the Bluetooth and WiFi dongles into the available USB ports.

Setting up WiFi is fairly simple:

1. Create the following file /etc/wpa_supplicant/wpa_supplicant.conf:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
	ssid="[YOUR SSID HERE]"
	proto=RSN
	key_mgmt=WPA-PSK
	pairwise=CCMP TKIP
	group=CCMP TKIP
	psk="[YOUR WPA KEY HERE]"
}

2. Modify /etc/network/interfaces to look like:

auto lo

iface lo inet loopback
iface eth0 inet dhcp

allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp

3. Restart your RaspberryPi and run ifconfig wlan0 to make sure it successfully receives an IP address.

If you see something similar to inet addr:192.168.1.25 Bcast:192.168.1.255 Mask:255.255.255.0 you should be able to shutdown your RaspberryPi, disconnect the keyboard and monitor, and login via SSH. The default login is pi / raspberry if you haven’t changed it.

RaspberryPi Configuration: Bluetooth

These steps were adapted from Instructables: Turn your Raspberry Pi into a Wireless Portable Bluetooth Audio System A2DP

Setting up Bluetooth is a bit more complicated:

1. Prerequisites

# Update apt repositories
> sudo apt-get update

# Upgrade packages 
> sudo apt-get upgrade

# Install bluez and bluez-tools
> sudo apt-get install bluez bluez-tools

# Install daemontools
> mkdir dt_inst
> curl -O http://cr.yp.to/daemontools/daemontools-0.76.tar.gz
> tar zxvf daemontools-0.76.tar.gz
> cd admin/daemontools-0.76
> curl -O http://www.qmail.org/moni.csi.hu/pub/glibc-2.3.1/daemontools-0.76.errno.patch
> patch -p1 < daemontools-0.76.errno.patch
> package/install
> csh -cf '/command/svscanboot &'

2. Name your device

Modify /etc/bluetooth/main.conf and change name to whatever you’d like.

Modify /var/lib/bluetooth/[mac address]/config and change name to the same name you just added above. You can find mac address by activating auto-complete (pressing tab) on the command line after you’ve entered /var/lib/bluetooth/.

3. Setup bluetooth agent for pairing support

To keep the pairing agent running permanently, we’ll start it as a daemon using Daemontools.

Create a service and log directory: mkdir -p /service/bluetooth-agent/log

Add the following run script to /service/bluetooth-agent/run:

#!/bin/sh

exec 2>&1
hciconfig hci0 piscan
exec /usr/bin/bluetooth-agent 0000

For logging, create the following run script in /service/bluetooth-agent/log/run:

#!/bin/bash
exec multilog t ./main

Make both run scripts executable: sudo chmod +x /service/bluetooth-agent/log/run /service/bluetooth-agent/run

If all is well, you should have the bluetooth-agent and log daemons running in the background. To check, run sudo svstat /service/bluetooth-agent. If the daemon reports that it’s only been up for 0 or 1 seconds, something is wrong. Run ps awux | grep readproctitle and check for errors.

At this point you should be able to scan for Bluetooth devices using your Android device and see the RaspberryPi. Pairing should also work by entering the pin code established in the run script.

Since I wanted to build an Android widget, I paired my Moto X with the RaspberryPi. Now the two devices can connect, but to actually do something useful we still need a way to send data between the Moto X and the RaspberryPi.

Simple Bluetooth Socket Server

We’re going to build a very simple Bluetooth socket server that waits for a connection, reads from it, responds, and then closes the connection. This is not robust by any means, but it’s easy to understand, serves a simple purpose, and can be expanded upon as necessary.

Create the following file called gate_srv.py:

import datetime, time, signal, sys
from bluetooth import *
import RPi.GPIO as GPIO

# Setup GPIO
PIN = 19
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN, GPIO.OUT, GPIO.PUD_DOWN, 0)

server_sock = BluetoothSocket(RFCOMM)
server_sock.bind(("", 10))
server_sock.listen(1)

port = server_sock.getsockname()[1]

uuid = '00001101-0000-1000-8000-00805F9B34FB'

advertise_service(server_sock, 'Gate', service_id=uuid, service_classes=[uuid, SERIAL_PORT_CLASS], profiles=[SERIAL_PORT_PROFILE])

def signal_handler(sig, frame):
	# Cleanup any open pins
	GPIO.cleanup()
	# Bail
	sys.exit(0)

def open_gate():
	print '{}: Opening gate'.format(str(datetime.datetime.utcnow()))
	GPIO.output(PIN, 1)
	time.sleep(2)
	GPIO.output(PIN, 0)

actions = {
	'OPEN_GATE': open_gate
}

def handle_conn(client):
  data = client.recv(1024)
	print data

	if data in actions:
	    actions[data]()

if __name__ == '__main__':
	signal.signal(signal.SIGINT, signal_handler)

	while True:
		print 'Waiting..'
		client_sock, client_info = server_sock.accept()
		print 'accepted..'
		handle_conn(client_sock)
		client_sock.send('OK')
		client_sock.close()


This script does a few things:

1. Sets up a GPIO pin (more on this later)

2. Initializes the Bluetooth socket and advertises a service

3. Sets up a signal handler to safely tear things down if the script receives a SIGINT (i.e. Control+C)

4. Creates a dictionary for command routing

5. Starts an endless loop that blocks waiting for a Bluetooth connection

We can start the script to check for any errors by executing: python gate_svr.py

If you receive any errors, make sure to double check for spelling mistakes and indentation. Raspbian should come with the rpi.gpio package, but if you don’t have it on your system, you can install it with sudo pip install rpi.gpio or sudo easy_install rpi.gpio

When running correctly, you should see Waiting... which means the server is waiting for an incoming connection. Now, we need a way to connect to the Bluetooth socket as a client and send a command.

Simple Android Widget

We’re going to build a simple Bluetooth client for Android in the form of a widget.

Start by creating a blank Android project in Android Studio or Eclipse.

Update AndroidManifest.xml to reflect the following:

This enables Bluetooth support and sets up receivers for the widget.

Next, we’ll create the class for the widget. Call it GateOpener.java:

package YOURPACKAGE.gateopener;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;


/**
 * Implementation of App Widget functionality.
 */
public class GateOpener extends AppWidgetProvider {

    public static String WIDGET_BUTTON = "YOURPACKAGE.gateopener.WIDGET_BUTTON";

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // Update all active widgets
        final int N = appWidgetIds.length;
        for (int i=0; i<N; i++) {
            updateAppWidget(context, appWidgetManager, appWidgetIds[i]);
        }
    }

    @Override
    public void onEnabled(Context context) {
        // Used when the widget is first created
    }

    @Override
    public void onDisabled(Context context) {
        // Used when widget is disabled
    }

    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
            int appWidgetId) {

        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.gate_opener);
        Intent intent = new Intent(WIDGET_BUTTON);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        views.setOnClickPendingIntent(R.id.btnOpen, pendingIntent);

        appWidgetManager.updateAppWidget(appWidgetId, views);
    }
}


This creates the functionality for firing an intent when the “Open Gate” button is tapped.

Finally, we’ll create the class that receives the Broadcast and makes the Bluetooth connection to the RaspberryPi. Much of the code below was adapted from http://developer.android.com/guide/topics/connectivity/bluetooth.html:

Be sure to replace NAME-OF-RPI-BLUETOOTH-DEVICE with the name you gave your Bluetooth device.

Lastly, create a layout with a button and place it in the layout directory of your Android project. Call the file gate_opener.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="@dimen/widget_margin"
    android:background="#c0c0c0" >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Open Gate"
        android:id="@+id/btnOpen"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="false"
        android:minWidth="300dp"
        android:minHeight="72dp" />
</RelativeLayout>

This is a very basic layout, so feel free to tweak it as desired.

Make sure the project builds successfully and installs onto your Android device.

Testing the GPIO output

Now you should have an Android Bluetooth client capable of sending a command to the RaspberryPi Bluetooth socket server. Remember the GPIO code from gate_svr.py? The RPi.GPIO package lets us control the GPIO pins on the RaspberryPi programmatically. Here, we start by setting the mode to BCM which allows us to use the pin numbering on the board instead of having to count the pins themselves. Next, we set pin 19 (no particular reason for this pin selection, but some pins do have special functionality, so do research before changing this) to OUTPUT and the internal pull up/down resistor to DOWN. This ensures the pin’s default state is LOW, otherwise, electrical interference and other environmental wackiness creates an ambiguous state on the pin.

When the correct command is received by the server, we set the pin’s OUTPUT to 1 (or HIGH) for 2 seconds and then set the pin’s OUTPUT back to 0 (or LOW). We also call a cleanup function in the signal handler to reset the pin back to its default state if the server receives a SIGINT.

At this point we can connect a ribbon cable to the GPIO pins and the Adafruit Pi Cobbler, then plug that into our breadboard. Now we can check the voltage on the GPIO 19 pin by placing a voltmeter between a jumper wire on the terminal strip attached to GPIO 19 and another jumper wire on the strip attached to a ground pin (see here for the RaspberryPi B+ pinout). Be extra careful not to bridge the GPIO pin and ground without the voltmeter between them. That will create a short circuit and probably burn out your pin or your RaspberryPi!

The voltmeter should read 0v until you tap the button in the widget, at which point the pin should be reading around 3v. There could be a bit of a delay with the Bluetooth connection, but no more than a second or two.

You can also experiment with placing a resistor and LED into the breadboard or any other projects that make use of a single GPIO output pin. But please don’t attach an LED to the GPIO pin without a resistor, you could burn out the pin this way too!

Prototyping the circuit

Now that you’re able to drive the GPIO pin via the Android widget, it’s time to build the circuit that operates the relay. Just like the GPIO pin can power an LED, it can also act as the low power input for our relay. Remember how I mentioned this particular relay becomes activated when the input is LOW and deactivated on HIGH? This is the trickier part to our circuit. We need to maintain a voltage on the relay’s INPUT pin and remove that voltage when the relay should activate, and thus complete the COMMON to CYCLE circuit in our gate opener. This is where the 2N2222 transistor comes into play. In the schematic below, the relay’s INPUT (IN1) has 3v applied to it when the GPIO 19 pin is LOW. Until the GPIO 19 pin is HIGH, the 2N2222 (Q1) prevents current from flowing through it. Activating the GPIO 19 pin applies 3v to the BASE pin, allowing current to flow through the transistor. When current is flowing through the transistor to ground, the amount of current available as INPUT to the relay is reduced significantly enough to activate it (remember, the relay is activated by a LOW input).

For safety’s sake, we also add a pull-down resistor (R3) in addition to using the RaspberryPi’s internal pull-down resistor that eliminates any small amounts of voltage that may be present when the GPIO pin is not set to HIGH.

The relay requires a 5v supply which can be conveniently connected to one of the 5v GPIO pins. Refer to the pinout diagram for the 5v pin locations.

schemeit-project (2)

Once you’re done you should have something like looks like this:

IMG_20141025_222320

 

Move your circuit to a solderable board

Once your prototype is tested and working as expected, you can move it to a circuit board. I bought these cheap ones from RadioShack, snapped them apart, and soldered the components and wires into place.

Battery connection

Attach wire connectors to the DC converter allowing you to make make the appropriate connections to the battery posts. A 90-degree microUSB cable can make it more convenient to power your RaspberryPi in a small enclosure because the connector itself takes up less room horizontally. Though not recommended, it is possible to remove the plastic sheath from a standard microUSB cable, revealing the metal connector. This greatly reduces the size of the connector, but increases the risk of damaging your components.

Find a suitable enclosure

The RaspberryPi B+, SainSmart relay, and the circuit boards all have mounting holes, but it can still be challenging finding a proper enclosure. RadioShack sells plastic and metal enclosures of various sizes, but if you want a small form factor you might have to work on a custom solution. A quick search will reveal several online marketplaces dedicated to 3D printing services and some UPS stores even offer 3D printing as a service.

If you do decide to 3D print your enclosure, pay special attention to where you’ll be attaching screws. Printed mounting posts can break easily when even light pressure is applied, so you may want to consider alternatives such as gluing short metal posts in place.

You can find the STL files below for the enclosure I designed that includes an opening for the USB, COMMON, and CYCLE cables. Several of my screw posts did break after one use though, so use this as a reference only. After assembly, I attached the lid with waterproof caulk and filled the cable port with it as well.

 

IMG_20141127_082343

 

 

Enclosure STL files (for 3D printing and modeling)

Enclosure-Full — Main part of enclosure where boards attach, has sides, and an opening for wires to pass through (should be closed with a waterproof sealant)

Enclosure-Top — Lid that should be attached with waterproof sealant

The latest print of these had at least one or two screw posts that were off by about a millimeter — depending on the model of printer and type of filament, you may have different (better or worse) results. Take accurate measurements of your layout and screw holes and adjust the design as need.

Go make things!

4 Responses to “RaspberryPi-powered Bluetooth Gate Opener”

  1. Jacob Cox

    I’m in the process of copying everything you did. Is there anything you have changed since making all of this? Is everything working the same way since day one?

    Reply
    • tim

      Hey Jacob!

      Everything’s still working as-is, and it’s survived a bad 12v battery and a fairly cold winter with snow piled on top of it.

      Reply
  2. Jason Cummins

    I did something very similar to this project last year, except instead of Bluetooth, I connected to the Pi using web server. The advantage I found using the web server is that I can open the gate from anywhere at any distance. Adding a web cam housed inside an old security camera housing also stepped up the project with a video feed from the gate. In the end, I made an android app that shows the video feed and also has a button that sends a signal to the Pi via the web server, which opens the gate. Saying all that, It has worked fine……except…..hack attempts. My Apache log stays full of Chinese hack attempts. The Pi would get hammered with Denial of Service attacks at least 3 times a month. I had to put in a daily reboot cron to make sure the gate was operational when I needed to get in. After a while, I just modified my IP Tables to help reduce the attempts. All in all, a pain in the butt. The Bluetooth method detailed here is definitely the way to go if you don’t want the headache of maintaining internet connectivity and those silly hackers looking for those secret government files I am storing on the Pi SD card at the gate.

    Reply
    • Jacob Cox

      Jason,

      Do you have the code or some example of what you created?

      I have used Apache before, but I’m not quite sure how to do that on the Pi.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *