Introduction: Alexa Raspberry Pi Relay Controller

I created this Instructable to share my experiences with integrating IOT devices with Amazon's Alexa.

This project allows a relay board connected to a raspberry pi to be controlled from smarthome controller.

It's been tested with Alexa but also seems to work fine with Samsung Smartthings and other control interfaces as it emulates a series of Belkin Wemo sockets.

There are LOTS of examples based on the excellent FAUXMO code but this meant learning python and didn't give me the detailed control i needed for my devices and so i decided to re-create one from scratch using C as my base coding language.

I also didn't want to have to go to the depths of lambda code on Amazon.com so i've kept it really simple.

I've posted the source and notes on Github :

https://github.com/Switchdoctorstu/StuPiMo

The tutorial is really to cover how to get it working and to publish my notes in case it helps others.

Step 1: Supplies and Connections

The things you need are readily available on Amazon / EBay:

  • Raspberry PI *
  • Pi power Supply
  • Dupont connectors
  • Relay Board
  • Old micro USB lead (to cut in half for power for the relay card)

Any raspberry Pi will work, i've tested this on a Model B and Zero.

*If using Pi Zero you'll need an OTG Network Adapter (unless you buy the 'W' version with buit in WiFi)

You'll need to connect the Pi to the network.

Use the dupont connetors to connect the relay card to the Pi.

Note that the relay card should use external power (remove the link and connect to external 5v). It will work powered from the PI but it's not advised for production running.

For my setup i used an externally powered USB HUB. This provides the power to the PI.

I also cut the end of an old USB cable and powered the relays from a 2nd USB connection to the hub to stay safe. My 'production' version uses a small 5V 5A switch mode power supply. Again i just cut a USB lead in half to power the Pi via Micro-USB and cut down two of the dupont connectors to power the relay board. There are 4 wires in the USB lead, most use red/black to denote the 5v supply but if in doubt use a meter to make sure you get the correct wires.

The relay pins on the board are connected to the relevant GPIO pins on the PI header.

The code allows you to choose the GPIO pins but the default i used was:

  1. Relay Pin 1 - Ground
  2. Relay Pin 2 - Relay 1 - GPIO 0
  3. Relay Pin 3 - Relay 2 - GPIO 1
  4. Relay Pin 4 - Relay 3 - GPIO 2
  5. Relay Pin 5 - Relay 4 - GPIO 3
  6. Relay Pin 6 - Relay 5 - GPIO 4
  7. Relay Pin 7 - Relay 6 - GPIO 5
  8. Relay Pin 8 - Relay 7 - GPIO 6
  9. Relay Pin 9 - Relay 8 - GPIO 7
  10. Relay Pin 10 - +5v for logic

Step 2: PI Setup

I'm not going to re-create a tutorial on how to get your PI up and running and connected to the network.

There are many guides including an excellent instructable at:

https://www.instructables.com/id/Ultimate-Raspberr...

You'll need to get yourself to the point where the PI is visible on the network and you can connect to it.

It doesn't matter whether this is via Ethernet or Wireless.

This project can be completed with just the Raspberry PI using the Geany Programmers Editor but i personally find it easier to do my code prep on a PC using Visual Studio or Eclipse (or even Notepad++) and then upload it to the PI for debugging using a VNC connection. Again i'm not going to cover that here as there are many excellent instructables on setting up VNC on an RPi.

All you need is to get to the point where you can upload and compile the code.

One note that is important is that since the UPNP handler requires UDP multicast, the interfaces used must be set to 'Promiscuous' mode.

This can be done on the command line:

pi@raspberrypi:~ $ ifconfig eth0 promisc

and / or

pi@raspberrypi:~ $ ifconfig wlan0 promisc

This needs to be made permanent so i edited the /etc/rc.local

sudo nano \etc\rc.local

to include the line:

sudo ifconfig eth0 promisc

after the first set of banner # lines to ensure that the interfaces were set on startup.

Step 3: Downloading and Compiling the Code

The code itself sits in my Github repsoitory;

https://github.com/Switchdoctorstu/StuPiMo/blob/ma...

whilst there are 'correct' ways to clone the repository. i found it easier just to open the Geany editor on the Pi desktop and paste the code in.

Similarly, if you're using the command line;

Create a new directory

mkdir Stu

Change to it

cd Stu

Make a new text file

nano StuPiMo.c

Copy the code from the Github raw and paste it into the new file

Save and exit.

Once you have the file as a C source code object you can compile it using

gcc -o StuPiMo StuPiMo.c -l wiringPi

note the "-l wiringPi" is needed to ensure that the compliler links in the required wiringPi library.

The code can then be run using

./StuPiMo


Again, if you want this to run on startup, use the command:

sudo nano /etc/rc.local

to add the following line

sudo /home/pi/Stu/StuPiMo &

to your /etc/rc.local file. Don't forget to save your file on exit.

Note the '&' is essential to ensure that a sub-process is spawned to ensure that the script isn't blocked at this point.


Step 4: Using It

Once you've got the code running, ask alexa to 'Discover Devices' and she should find all 8 of the virtual Wemo devices.

Then it's just a case of saying: "Alexa turn on socket 1" or "Alexa turn off socket 6" etc. and the relevant relay will be changed.

Step 5: How the Code Works

The code works by emulating a series of Belkin Wemo socket devices.

To acheive this it has to handle 2 major functions

  • a UPNP discovery broadcast handler
  • a 'device handler' (one per virtual device) to manage the commands sent to the device and the required responses.

A 'bonus' feature is that it also publishes a web page to allow contol of the devices.

UPNP Handler

The UPNP handler opens a socket to monitor SSDP protocol packets on 239.255.255.250 port 1900.

It responds to any 'M-SEARCH' queries coming in with a discovery response packet that anounces the individual wemo emulators to anyone who asks.

Device Handler

The device handlers (one per virtual device) monitor a series of IP ports and responds to requests.

It will serve a setup.xml response when asked

It will serve an event description file when asked

It will respond to a GETBINARYSTATE request

It will process and respond to a SETBINARYSTATE request

Web Server

The web server is a simple routine that builds a HTML form containing a button per relay.

It will respond to the buttons being pressed and toggle the state of the relay accordingly.

Step 6: Customisation and Friendly Names

I've not gone mad with the code to keep it simple and editable.

The basics can be customised by definitions at the start of the code:

// global definitions
#define WEBPORT 5353 // port to run the web server on

#define NUMDEVICES 8 // Number of virtual devices to create

#define PORTBASE 43450 // base IP port to increment up from

WEBPORT is the port number that the in-built web server runs on. This could be made to sit at 80 to make things easy but i found that it conflicted with tomcat or other services running locally.

NUMDEVICES defines the number of individual WEMO emulators to launch. If you have a 2 port relay card then set this to 2, 4 port = 4 etc.

The friendly names for the devices are set in a routine called setup_names:

int setup_names(char friendly[NUMDEVICES][NAMELEN]) {
int i = 0;

// use this loop

for (i = 0; i < NUMDEVICES; i++) {

sprintf(friendly[i], "Socket %d", i + 1);

}

// or the following manual table to populate device names

/*

strcpy(friendly[0], "Bedroom TV");

strcpy(friendly[1], "Electric Blanket");

strcpy(friendly[2], "Bedroom Lamp");

strcpy(friendly[3], "Socket 4");

strcpy(friendly[4], "Socket 5");

strcpy(friendly[5], "Socket 6");

strcpy(friendly[6], "Socket 7");

strcpy(friendly[7], "Socket 8");

*/

return i;

}

I used a loop to call each of the devices 'Socket n' but you can delete this loop and add your own friendly names instead (just make sure that you add the same number as NUMDEVICES) if you delete the /* */

Remember to re-compile the code if you make any changes.