Thursday, February 7, 2013

Web connected outlet - Epilogue

Finishing

I boxed everything up today, poked some holes in the cover so it could breathe and tested everything one last time before plugging it in.  The app autostarts about a minute after plugging it in so it truly is a headless device.

The box is rather large, but I wanted plenty of space. Putting stuff in boxes is often the hardest part for me.  I typically have to drill extra holes to get everything aligned and screwed together.  This time, I used the time-honored tradition of "measure twice, cut once" and it turned out pretty well.  The next one will be in a smaller box and will use the Raspberry Pi Model A.

Why do this?

When I decided to do this project, I mostly wanted to learn a little more about the RPi and to prove a point (again): if you can think it, you can do it.

At some point the "doing it" gets easier and the "thinking it" gets harder. There are so many people thinking and doing ("makers") that by the time you think of something, someone else has probably already done it - and maybe they're even selling it!  For example, Belkin makes a relatively inexpensive system called WeMo that does the same thing as this project a little more elegantly and for about the same cost.  I just saw a really cool Siri/Raspberry Pi system on Life Hacker that handles lights, garage doors, etc. using off-the-shelf components.

But, regardless of the utility or the uniqueness of these little innovations, the fun is really in the learning and testing and experimenting and just playing with the technology. It's way more fun than watching TV (with the possible exceptions of Big Bang Theory or Modern Family) and playing video games (with the possible exception of Pong.)

I believe that the next big thing is the "Internet of things" so I try to nudge it along whenever I can. So, what's the next project? Maybe one that has to do with things!

Monday, February 4, 2013

Web connected outlet - part 6


The software

The WebIOPi software, developed by Eric Ptak and featured in this month's MagPi magazine, has some great, easy to use software for manipulating GPIO ports.  If you're doing GPIO, you owe it to yourself to check this out.  Most of the code below started from the WebIOPi examples, except for the C code (which started out as code by Kevin Sangeelee, released as GPLv2.)

I've skinnied down his WebIOPi Javascript code to simply turn on and off a single port.  These web apps are stored in /usr/share/webiopi/htdocs on the RPi and are called, imaginatively, on.html and off.html. Here's what they look like:

on.html

<html>
<head>
<title>Switch 1 on</title>
    <script type="text/javascript" src="webiopi.js"></script>
    <script type="text/javascript">
        webiopi().ready(function() {
            webiopi().setFunction(7,"OUT");
            webiopi().setValue(7, 1);
        });
    </script>
</head>
<body>
<FORM METHOD="post">
    <INPUT TYPE="button"
        VALUE="Back"
        OnClick="history.go(-1);return true;"">
</FORM>
</body>
</html>


off.html

<html>
<head>
<title>Switch 1 off</title>
    <script type="text/javascript" src="webiopi.js"></script>
    <script type="text/javascript">
        webiopi().ready(function() {
            webiopi().setFunction(7,"OUT");
            webiopi().setValue(7, 0);
        });
    </script>
</head>
<body>
<FORM METHOD="post">
    <INPUT TYPE="button"
        VALUE="Back"
        OnClick="history.go(-1);return true;"">
</FORM>
</body>
</html>


They're really quite simple and they work. I picked GPIO 7 because it's the last pin in the header on the outboard side. (It's the easiest to locate without counting pins.)

From a browser just access these two web pages to turn on and off port 7:

http://192.168.1.210:8000/on.html
http://192.168.1.210:8000/off.html

I can also call these from a web page running on my mac from a couple of buttons. The html on the mac looks like this:

<html>
<body>
<FORM METHOD="post">
    Switch 1
    <INPUT TYPE="button"
        VALUE="On"
        OnClick="window.location='http://192.168.1.210:8000/on.html'">
    <INPUT TYPE="button"
        VALUE="Off"
        OnClick="window.location='http://192.168.1.210:8000/off.html'">
</FORM>
</body>
</html>

Pretty simple... Obviously, you can make these web pages arbitrarily complex, or you could just use the demo code that Eric provides. But for this purpose, the simpler the better.

There are also libraries that allow you to do GPIO manipulation in C.  Here's a C program that turns on and off port 7:


#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#define IOBASE   0x20000000
#define GPIO_BASE (IOBASE + 0x200000)
#define GPFSEL0    *(gpio.addr + 0)
#define GPFSEL1    *(gpio.addr + 1)
#define GPFSEL2    *(gpio.addr + 2)
#define GPFSEL3    *(gpio.addr + 3)
#define GPFSEL4    *(gpio.addr + 4)
#define GPFSEL5    *(gpio.addr + 5)
// Reserved @ word offset 6
#define GPSET0    *(gpio.addr + 7)
#define GPSET1    *(gpio.addr + 8)
// Reserved @ word offset 9
#define GPCLR0    *(gpio.addr + 10)
#define GPCLR1    *(gpio.addr + 11)
// Reserved @ word offset 12
#define GPLEV0    *(gpio.addr + 13)
#define GPLEV1    *(gpio.addr + 14)
#define BIT_7 (1 << 7)
#define PAGESIZE 4096
#define BLOCK_SIZE 4096

struct bcm2835_peripheral {
    unsigned long addr_p;
    int mem_fd;
    void *map;
    volatile unsigned int *addr;
};

struct bcm2835_peripheral gpio = {GPIO_BASE};

// Some forward declarations...
int map_peripheral(struct bcm2835_peripheral *p);
void unmap_peripheral(struct bcm2835_peripheral *p);

int gpio_state = -1;

////////////////
//  main()
////////////////
int main(int argc, char *argv[]) {

    if(argc == 2) {
        if(!strcmp(argv[1], "on"))
            gpio_state = 1;
        if(!strcmp(argv[1], "off"))
            gpio_state = 0;
    }
    if(map_peripheral(&gpio) == -1) {
        printf("Failed to map the physical GPIO registers into the virtual memory space.\n");
        return -1;
    }
    GPFSEL1 &= ~(7 << 21); // Mask out bits 23-21 of GPFSEL1 (i.e. force to zero)
    GPFSEL1 |= (1 << 21);  // Set bits 23-21 of GPFSEL1 to binary '001'

    if(gpio_state == 0)
        GPCLR0 = BIT_7;
    else if(gpio_state == 1)
        GPSET0 = BIT_7;

    usleep(1);    // Delay to allow any change in state to be reflected in the LEVn, register bit.
    printf("GPIO 7 is %s\n", (GPLEV0 & BIT_7) ? "high" : "low");
    unmap_peripheral(&gpio);
}

// Exposes the physical address defined in the passed structure using mmap on /dev/mem
int map_peripheral(struct bcm2835_peripheral *p)
{
   // Open /dev/mem
   if ((p->mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
      printf("Failed to open /dev/mem, try checking permissions.\n");
      return -1;
   }
   p->map = mmap(
      NULL,
      BLOCK_SIZE,
      PROT_READ|PROT_WRITE,
      MAP_SHARED,
      p->mem_fd,  // File descriptor to physical memory virtual file '/dev/mem'
      p->addr_p      // Address in physical map that we want this memory block to expose
   );
   if (p->map == MAP_FAILED) {
        perror("mmap");
        return -1;
   }
   p->addr = (volatile unsigned int *)p->map;
   return 0;
}
void unmap_peripheral(struct bcm2835_peripheral *p) {
    munmap(p->map, BLOCK_SIZE);
    close(p->mem_fd);
}


Finally, la pièce de résistance: there's also a RESTAPI provided with WebIOPi that you can use to turn on and off GPIO ports - here is how you turn on a port using the curl interface to issue REST POSTs from a Mac:

curl -X POST http://192.168.1.210:8000/GPIO/7/function/out
curl -X POST http://192.168.1.210:8000/GPIO/7/value/1

Even easier than the web interface! As with anything on the Pi, there are a dozen ways to do it! I'll probably use the RESTAPI method with a cron schedule on the Mac to turn lights on and off when we're away.

When the RPi model A's come out, I expect I'll use a couple of them to build some more of these.  Pretty simple and useful tools!

Next time: packaging and wrap up (still waiting for the box to put it in...)

Sunday, February 3, 2013

Web connected outlet - part 5

Headless WiFi Pi

Hooking up wireless on the Pi is pretty easy.  Here's the high-level process:
- Start out by connecting a monitor, keyboard and a downloaded image on your SD card
- During configuration, select that you want SSH installed and running
- Hook up your ethernet connection
- Reboot
- Log in via the keyboard and do an ifconfig to get the IP address of the Ethernet adapter (or just monitor your router during the reboot to see what new IP address shows up. Ethernet defaults to dhcp so you can't predict what IP address it will be...)
- ssh from your computer to the IP address of the Ethernet adapter.  I use this with the password raspberry
All wired up - sans case.
Don't touch anything!
ssh pi@192.168.1.27
- modify /etc/network/interfaces so it looks something like this:
auto lo
iface lo inet loopback
 
auto wlan0
iface wlan0 inet static
wireless-essid [your-wifi-ssid]
address 192.168.1.210
netmask 255.255.255.0
gateway 192.168.1.1
dns-nameservers 192.168.1.1 8.8.8.8
 
auto eth0
iface eth0 inet dhcp
- plug in your WiFi USB device into the empty USB port on the RPi
- reboot and disconnect your wired connection, keyboard and monitor - you're WiFi headless now.
- you should now be able to connect to the IP address you set up above. (You can always reconnect the wired Ethernet, or connect a monitor and keyboard if something goes wrong.)

Obviously, you'll want to use your own network's ssid and IP subnet.  For these devices, I use an unprotected WiFi network (you'll probably want to use WPA.)  There are lots of good Raspberry Pi wireless configuration resources; just google it...

Note that eth0 follows wlan0 in the file, above. I did this because, if it's not connected to anything, the eth0 connection continuously tries to connect and may just sit there waiting for a long, long time, before the wireless connection gets configured [at least this is my speculation - I couldn't get a wireless connection until I moved eth0 down.]


The WiFi USB device I'm using I got from Newark.com for about $16 [at left.] (For some reason, at this time, the picture on the Newark web page shows something different than what you actually get. View the "Technical Data Sheet" for an image of the actual device.)  I've used a couple of other small USB wireless adapters, but found that this one seems to be most reliable. One of the others apparently had a short and was actually smoking when I pulled it out of the USB port (with my bare hands, BTW. You gotta be tough to be a geek.)


Next time: the web page.

Saturday, February 2, 2013

Web connected outlet - part 4


Connecting the pieces

This is the dicey part.  Dealing with 120VAC is potentially lethal. So, if you don't know what you're doing, don't do it. You've been warned.

So far, I've cobbled together a transistor switch that will allow a GPIO output pin to open and close a relay. I wired it up on a little Radio Shack project breadboard and tested it with 5V on the relay and a 3.3 V signal.  I've loaded the software on the RPi and demonstrated that it controls the GPIO.  I tested the breadboarded relay with the GPIO software just to hear that satisfying click one more time...

Danger, Will Robinson!

 When you're wiring up the circuit to the mains there are some things to be careful of:
- separate the low-voltage and high-voltage parts of the system as much as possible.
- insulate the high-voltage parts
- include a properly rated fuse to keep the house from burning down if there's a problem
- solder everything together - don't just twist wires together and wrap them in electrical tape...
- tie down any loose wires and bolt the components to the case
- remember the wiring codes / color codes for your location - they're there to protect you. In the US, black is hot, white is neutral and green is ground.  On electrical cords and sockets in the US, the wide spade is neutral (wide/white/neutral is how I remember it) and the narrow spade is hot. The round pin is ground.
- protect the system from poking fingers and pets (put it in a box)

I've hacked apart a small 5V 2A supply from a wall wart that was used for some equipment that's no longer in use and shortened the mini-USB cable to hook up to the RPi.

Exciting Video:
Test setup on the bench
Here's a link to a video of me switching on and off a table lamp. Before you watch this, you should sit down and scooch toward the edge of your chair - just to be prepared. It's riviting stuff. http://youtu.be/69POMqXjwls

I didn't have a plastic case that will fit all the pieces, so I ordered a couple of plastic project cases from Amazon.  I'll box it up when they arrive in a week or so. (I'll drill some holes in the case so the RPi can breathe.)

While I'm waiting, I'll get this hooked up to the WiFi network - I've just been using an Ethernet connection for the testing.  I'll discuss this next time.