230V Air Conditioner and HomeKit, part 5: GPIO

In part 3 of project blog, I described setting up a Raspberry Pi. In part 4 I went over how I installed Homebridge on the RPi so that it could communicate with Apple’s Homekit.

Everything I described in those two parts did not require a Raspberry Pi; I could have done it on my desktop Mac. Now we come to the part that makes the RPi useful: The ability to easily access the pins on the printed-circuit board.

RPi closedup

In the above picture, you can make out the pins on the RPi board near the bottom. (In retrospect, I should have removed the case cover for the photo.) The Raspberry Pi gives you a relatively easy way to control those pins.

Here is a description of the RPi 3B+ pins. The diagram from that page is:

RPi pins

I needed some help from Sam Groveman to understand this diagram. Here’s a longer description than the one he gave, since I have trouble being brief:

  • The small number next to the picture of a pin is the physical pin number, the one you get if you just count the pins across and down.
  • The big, bold numbers on the right and left sides of the diagram are the GPIO numbers assigned to the pin in the WiringPi package (more on this below).
  • The text between the numbers refers to the electrical function of the pin.
  • This page gave me the basic idea of what I’d have to do (even though the technique described uses an Arduino instead of directly using the Raspberry Pi). I would need to send signals to two solid-state relays in order to control power to my 230V air conditioner.

    Why two relays? All of pages I found on Raspberry Pi control of appliances using solid-state relays (SSRs) assumed that the RPi would only have to affect a single power wire. This is because those appliances used a NEMA 5-15 plug:

    NEMA 5-15

    In the above picture, you’ll see that only one hole in that nicely-labeled socket is “hot”, that is, it’s the only one that carries 115 volts. If I want to turn off the power to a device with a NEMA 5-15 plug, it’s sufficient to cut the power to the “hot” wire.

    My air conditioner uses a NEMA 6-15 plug:

    NEMA 6-15

    While the topmost hole is still ground, the bottom two horizontal holes are both at 115 volts. So to turn off my air conditioner, I have to cut power to both “hot” wires.

    (115V + 115V = 230V, which sounds like a consistent bit of math given that I talk about a 230V air conditioner. Actually, if the two wires are out-of-phase and come from three-phase power, the result is 208V. As I said in part 2, I can’t tell which applies to my air conditioner, but it doesn’t matter for the purposes of this discussion.)

    (Could I get away with just cutting the power to one of those two hot wires? According to a friend of mine who works with electrical circuits, it would probably have the same effect as a brown-out. The motor would try to continue running and would burn out. Maybe modern air conditioners would handle it differently, but my A/C is about 40 years old.)

    So I need to control two solid-state relays; I’ll describe the SSRs in more detail in the next blog post for this project. That means I need to control two pins on the Raspberry Pi to turn those relays on and off, plus two more pins that are permanently set to ground in the above diagram.

    Fortunately, the Raspberry Pi operating system, Raspian, comes with the WiringPi package. The key program that’s useful for my project is gpio. Here’s what I see when I use the ‘gpio readall’ command on my Raspberry Pi:

    $ gpio readall
     +-----+-----+---------+------+---+---Pi 3+--+---+------+---------+-----+-----+
     | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
     +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
     |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
     |   2 |   8 |   SDA.1 |   IN | 1 |  3 || 4  |   |      | 5v      |     |     |
     |   3 |   9 |   SCL.1 |   IN | 1 |  5 || 6  |   |      | 0v      |     |     |
     |   4 |   7 | GPIO. 7 |  OUT | 0 |  7 || 8  | 0 | IN   | TxD     | 15  | 14  |
     |     |     |      0v |      |   |  9 || 10 | 1 | IN   | RxD     | 16  | 15  |
     |  17 |   0 | GPIO. 0 |   IN | 0 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |
     |  27 |   2 | GPIO. 2 |   IN | 0 | 13 || 14 |   |      | 0v      |     |     |
     |  22 |   3 | GPIO. 3 |   IN | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |
     |     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |
     |  10 |  12 |    MOSI |   IN | 0 | 19 || 20 |   |      | 0v      |     |     |
     |   9 |  13 |    MISO |   IN | 0 | 21 || 22 | 0 | IN   | GPIO. 6 | 6   | 25  |
     |  11 |  14 |    SCLK |   IN | 0 | 23 || 24 | 1 | IN   | CE0     | 10  | 8   |
     |     |     |      0v |      |   | 25 || 26 | 1 | IN   | CE1     | 11  | 7   |
     |   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |
     |   5 |  21 | GPIO.21 |   IN | 1 | 29 || 30 |   |      | 0v      |     |     |
     |   6 |  22 | GPIO.22 |  OUT | 0 | 31 || 32 | 0 | IN   | GPIO.26 | 26  | 12  |
     |  13 |  23 | GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v      |     |     |
     |  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |
     |  26 |  25 | GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |
     |     |     |      0v |      |   | 39 || 40 | 0 | IN   | GPIO.29 | 29  | 21  |
     +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
     | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
     +-----+-----+---------+------+---+---Pi 3+--+---+------+---------+-----+-----+

    This is similar to the diagram above, but with a few more columns.

    • The “BCM” columns refer to the wires coming out of the main processor chip of the Raspberry Pi, and can be ignored for this project.
    • The “Mode” column indicates whether the pin is set to reading signals (IN) or sending signals (OUT).
    • The “V” column, at least for wires that send signals, indicates whether the pin is at 3.3V (V=1) or 0V (V=0).

    I knew I was going to have to connect wires from the Raspberry Pi to the relays. To make things easier on myself, I purchased jumper cables:

    Jumper Cables

    The individual cables peel off cleanly from the wide strip, and the black tips fit nicely over the Raspberry Pi’s pins.

    (Sam Groveman initially suggest that I get a Raspberry Pi Zero W, which is smaller and less expensive than the Raspberry Pi 3 B+ I purchased. However, I would have had to solder wires directly to the smaller RPi’s circuit board.

    (I’ve soldered electrical circuits before, but that was when I worked with Heathkits as a teenager. I figured that fine work that a 14-year-old could handle might be a bit much for someone in his 50s, and went with a bigger RPi and jumper cables. After all, while 14-year-old me had better eyesight, the current me has more disposable income.)

    With lots of pins to choose, I arbitrarily chose pin 29 (GPIO.21) and pin 9 (ground) to form the control circuit for the first relay, and pin 31 (GPIO.22) and pin 39 (ground) to control circuit the second relay.

    I’ve picked my pins, and I’ve set up Homebridge. Now I needed a link between the two. There are several Homebridge plugins for directly controlling Raspberry Pi pins, but all the ones I found would only control one pin at a time. I decided to use the homebridge-cmdswitch2 plugin, which allows you to run your own UNIX commands via HomeKit.

    Installing homebridge-cmdswitch2 was simple:

    npm install -g homebridge-cmdswitch2

    I then had to write the commands that this plugin would execute. I decided to write a single script using the Bash shell, because it’s easier to execute command-line programs like ‘gpio’ directly from the script.

    Here is what I wrote in /home/seligman/multi-pin.sh:

    #!/bin/bash
    # 08-Jul-2018 WGS
    
    # Script to control the operation of multiple pins on the Raspberry Pi
    # at the same time. Here it's used to control multiple relays that
    # affect the power going to my 230V (or maybe 208V) air conditioner.
    
    # Define some commands, to save typing later.  I use the complete
    # paths to invoke commands, so I don't have to worry about the value
    # of $PATH.
    GPIO=/usr/local/bin/gpio
    ECHO=/bin/echo
    
    # A bash array containing the pins I want to control.  With only two
    # pins, I could do this with a couple of "if" statements instead of
    # loops, but I like to (a) show off, and (b) create generalized code.
    PINS=(21 22)
    
    # Note that I chose to identify pins using their WiringPi
    # numbers. If I wanted to use the physical pin numbers instead:
    # GPIO="/usr/local/bin/gpio -1"
    # PINS=(29 31)
    
    function start {
        # Loop over PINS array
        for PIN in "${PINS[@]}"
        do
    	# Set the pin to output and turn it on
    	$GPIO mode ${PIN} output
    	$GPIO write ${PIN} 1
        done
    }
    
    function stop {
        # Loop over PINS array
        for PIN in "${PINS[@]}"
        do
    	# Set the pin to output and turn it off
    	$GPIO mode ${PIN} output
    	$GPIO write ${PIN} 0
        done
    }
    
    function status {
        for PIN in "${PINS[@]}"
        do
    	# If a pin is off, exit with an error code.
    	# Backticks mean "execute the command and return
    	# the command's output". 
    	if [ `$GPIO read ${PIN}` == 0 ]
    	then
    	    exit 1
    	fi
        done    
    }
    
    # $1 is the first argument to this script.
    
    case "$1" in
        start)
    	start
    	;;
        stop)
    	stop
    	;;
        status)
    	status
    	;;
        *)
    	$ECHO $"Usage: $0 {start|stop|status}"
    	exit 1
    esac

    I made the script executable:

    chmod +x /home/seligman/multi-pin.sh

    I tested this script by executing commands like the following, and observing changes to the pins’ state with ‘gpio readall’:

    /home/seligman/multi-pin.sh start
    /home/seligman/multi-pin.sh stop
    /home/seligman/multi-pin.sh status

    Everything worked!

    Then I edited the Homebridge configuration file, /var/lib/homebridge/config.json, to include the homebridge-cmdswitch2 plugin:

    {
        "bridge": {
    	"name": "Homebridge",
    	"username": "B8:27:EB:8F:C5:D7",
    	"port": 45525,
    	"pin": "031-45-154"
        },
        "description": "SmartHome with Homebridge",
        "platforms": [{
    	"platform": "cmdSwitch2",
    	"name": "CMD Switch",
    	"switches": [{
    	    "name": "Air Conditioner",
    	    "on_cmd": "/home/seligman/multi-pin.sh start",
    	    "off_cmd": "/home/seligman/multi-pin.sh stop",
    	    "state_cmd": "//home/seligman/multi-pin.sh status"
    	}]
        }]
    }

    (I had to use the JSON Syntax Checker several times to get all those brackets in the right place.)

    I restarted homebridge so it would use the new configuration file:

    sudo systemctl restart homebridge

    After I did this, I saw that the Eve iOS app on my iPhone recognized “Air Conditioner” as a full-fledged HomeKit accessory, with an ON/OFF switch.

    I spoke into my iPhone: “Turn on the air conditioner.” Siri responded, “Your air conditioner is on.” I attached a voltmeter to the ends of the wires connecting to pins 29 and 9, and saw:

    Air conditioner on

    3.3V (or close enough)!

    Then I spoke to my iPhone again: “Turn off the air conditioner.” Siri responded, “Your air conditioner is off.” And I saw the voltage change:

    Air conditioner off

    I tested this several times, both on pins 29 and 9, and on pins 31 and 39. It all works. HomeKit can control my Raspberry Pi’s pins.

    The next step: Solid-state relays. As a bonus: why there’s a fan connected to the Raspberry Pi in the above two pictures.

This Post Has 0 Comments

Leave a Reply