Controlling Relays with a Raspberry Pi

Ever wanted to control some real world hardware with your Raspberry Pi? Every now and then, we get questions about using either our I2C-RELAY16 or I2C-XIO boards from the Pi, and it’s been on my eternal backlog list of “I should do a quick article on that…” So let’s break this logjam and get down to controlling a cheap Chinese 16 channel relay board with a Pi (available from SainSmart and others). Because this provides 16 relatively high current, isolated output channels, this seems a great place to start, and it’s an easy hour project.

A Raspberry Pi 3 controlling a 16-channel relay module on my bench

Connecting I2C to the Pi

The first thing to consider is that the Pi is 3.3V and most of our I2C boards are targeted at 5V systems. Michael built something called the RPI-5VI2C a while back – it’s essentially a tiny daughterboard that plugs in the Pi’s HAT connector, level shifts the I2C up to 5V, puts on the required pull-up resistors and brings the bus out on ISE’s standard 6p6c I2C modularconnector. Here’s the schematic if you want to take a look. It’s not a product yet, but it likely will be shortly. We want to flip it over, add some ESD protection, and provide both 5V and 3.3V I2C jacks before we make it a real product.

A tiny I2C interface for the RasPi, including a 5V level shifter and pull-up resistors

Getting I2C Set Up On the Pi

By default, the I2C subsystem on the Pi isn’t active. There are plenty of tutorials about this, however, and they’re all better written than what I could do. I’ll refer you over to the one at Adafruit, which is how I learned how to do it. Basically, if you’re using Raspbian, it’s installing two packages (python-smbus and i2c-tools) and then going into one configuration menu. It’s dirt simple.

Connecting the Relay16

Obviously for this part you’re going to need an I2C-RELAY16 board and probably the cheap 16-channel relay board that goes under it. Just hook it into the level-shifting interface on the Pi with a straight-through 6p6c cable (pin 1 to pin 1, otherwise bad things will happen).

You’ll also need to provide 12V power to the relay board. Those relays run on 12V, and that’s not going to come over from the Pi. Plus, they draw a fair amount of current when they’re actually on.

If everything is connected right, you should be able to run the following command and (assuming all address jumpers are set to the low, or not-dot) position, you should see something at address 0x20:

sudo i2cdetect -y 1

Controlling it with Python

When it comes to scripting languages, python’s really hard to beat. It’s simple, quick, and you can do almost anything with “import some-module”.

In this case, I’ve made a class called “relay16” – it’s a really simple wrapper around the smbus calls needed to run the PCA9671 part on the I2C-RELAY16 board. The example code is in the src/RasPi-Python subdirectory of the I2C-RELAY16’s Github project.

So, covering this generally, we’re importing modules for controlling smbus (a specialized subset of I2C for managing sensors and such attached to computers), the relay16 library, and the time library (so that we can have some delay).

The first thing we do is then initialize an smbus instance connected to bus #1. The processors on the Pis have (at least) two I2C busses. Every Pi except the 256Mb version of the Pi 1 uses bus #1. That one particular variant of the Pi 1 uses bus 0. So we’ll make our example use bus #1 and that will work for most cases.

The address of the I2C-RELAY16 module will vary based on how you have the jumpers set, but if they’re all set away from the dots, you’ll have an address of 0x20. So let’s just assign that to a variable so it’s easy to change.

Now’s where the fun starts.

relayBoard = relay16.relay16(bus, address)

This line creates a relay16 object that the system knows is attached to the smbus #1 (because we created the bus object with those parameters earlier) at address 0x20.

At this point, we can just start turning relays on and off. setRelay(n) will turn on relay #n and clearRelay(n) will turn it off. clearAllRelays() will shut them all down.

That’s pretty much it in a nutshell. If you run “sudo python i2ctest-relay16.py” you’ll see it run around the relay board, turning each sequential relay on for a tenth of a second.

Comments

We wanted to change a few things about its form factor so that it didn’t block the display connector (and provided pass-through power pins for the official touch-screen), but we’ve got ten of the original prototypes. If you wanted to give it a shot and provide feedback about using Pis, I2C, and whatever else in model railroading, we would definitely send you one. Just drop us a note back-channel at support@iascaled.com and we’ll get you one.

Would the I2C-RELAY16 work on one of the 8-channel relay boards? It looks like you could just use one row of the connector. Also looking forward to availability of the RPI-5VI2C. Do you think it would be compatible with the LiFePO4wered/Pi3 UPS?

Yes, theoretically the RELAY16 should work with the usual 8 channel boards by just plugging it in half of the header (making sure, of course, that you’ve got the polarity correct). The only gotcha would be that the 16 channel boards have an onboard power supply, and the I2C-RELAY16 depends on this to function. So, you would need to feed 5V power in from somewhere as well.

Based on what I’ve read, you should be able to control I2C devices on the Pi from inside Win IoT. This sample they’ve got on controlling a Microchip port expander would probably be a good starting point, as while not identical to the PCA9671 used on the I2C-RELAY16, it’s very similar.