Electronics, Raspberry Pi, Tutorials

How to create a simple IOT device with PHP on a Raspberry Pi Zero W

Introduction

Following on the “PHP on Raspberry” train, I wanted to create something simple enough to use as a demo, however it should be useful and it should include some simple components to show how easy it is to build a little gadget using PHP on Raspberry. I’m not gonna go into detail about “why PHP” and I also won’t enter any language shaming discussion – that being said, just keep in mind, in case you don’t know this yet, that modern PHP is a cheap, accessible and popular language that can be used not only for web, but also for command line scripts.

I eventually came to this idea of a dumb smart button. It consists basically of a button that will make a request to a pre-defined URL every time it’s clicked, and an RGB LED that will indicate the status of the request. Using simple components and modern PHP code, this is just the perfect little project to showcase the world of possibilities you can build with the language you already know and love! 😀

This tutorial will show you how to create a simple circuit on top of a Raspberry Pi Zero W, using a button and an RGB LED, and how to create a basic PHP command-line application for interacting with these components. We’re gonna use the Composer library PiPHP/GPIO to interact with the components. This library has a few limitations but it doesn’t require installation of modules or other stuff, so it’s the easier way to work with basic components in PHP.

Requirements

  • 1x Raspberry Pi Zero W
  • 1x RGB LED
  • 1x Push button
  • 3x 220 ohm resistor (for the LED)
  • 1x 10k ohm resistor (for the button)
  • breadboard, female-male and male-male breadboard jumper wires

Step 1: Set Up Raspberry Pi Zero W

Initial Setup and Configuration

It’s recommended to get a new, fresh install of Raspbian Stretch on your Raspberry Pi Zero W before going any further. We’ll need an up-to-date and stable version of Raspbian Stretch in order to install PHP in the next step.

The detailed instructions on how to do so can be found in this tutorial: Raspberry Pi Zero W Detailed Setup Guide . Come back here when your Raspberry Pi Zero have access to the Internet and you are able to execute commands via either SSH or by connecting a display and keyboard and opening the terminal app (tip: when on the GUI, press ctrl + alt + t to open a new terminal).

Installing PHP

The default repository for Raspbian Stretch contains PHP 7.0, however, version 7.1 has important performance improvements and the newest versions of major frameworks had already migrated to require 7.1. The examples in this post won’t require PHP 7.1, however it’s a good idea to update if you plan on doing more stuff with it.

If you’d like to install 7.1 you can follow my other tutorial: Installing PHP 7.1 on Raspbian Stretch (Raspberry Pi Zero W) in order to install PHP 7.1 on your Raspberry Pi Zero W. Otherwise, you can install PHP 7.0 (command-line only is sufficient) with:

sudo apt-get install php7.0-cli

Installing Composer

We are going to use Composer for installing the PiPHP/GPIO library. Please refer to the official Composer docs for installation instructions.

Step 2: Create the circuit

Now that the system is a go, we need to work on the little circuit that will connect the LED and the button to your Raspberry Pi Zero W. For the button I’m using pin 21, just because it’s easy to find. For the LED I chose pins that have support to PWM, however the library we’re using doesn’t support this feature so it won’t really matter if you choose different pins. PWM stands for Pulse Wave Modulation, and they basically emulate analog signals, enabling us to use a range of values instead of just one and zero when sending output to the pins.

For a reference on the Raspberry Pi Zero W pinout, check this Sparkfun datasheet.

This is how our wiring should look like:

The important bits that will be reflected on our code: button is attached to pin 21, LED is attached to pins 13 (RED), 19 (GREEN) and 12 (BLUE).

*If this is all new to you, please have a look at this entry-level tutorial: Getting Started with Raspberry Pi: LED blinking on Raspberry Pi Zero.

RGB LEDs are in fact composed by three little LEDs (red, green, blue) encapsulated into one. Each individual color is driven by one leg of the LED. One extra leg is shared between the three internal LEDs, and depending on the LED type it should be connected to either GND or current (5/3.3V). This diagram is using a common cathode LED, which means the common leg is a cathode (negative) and should be connected to GND. In case what you have is a common anode, the shared leg should be connected to the input current (5V or 3.3V). The shared leg is easily identifiable because it’s the longer leg.

An RGB LED requires the use of 3 GPIO ports, where each leg should be connected through a resistor – a value of 220 ohms is generally a good choice, but you can also use values up to 1k (more resistance means less intensity).

Testing the Circuit with PHP

Before we go about creating an actual app that interacts with the Internet, let’s test the circuit with a simple PHP script that will light up the LED whenever the button is pressed. This will allow us to check if the wiring is correct and also give us a base to build from.

Let’s create a folder for our app and download the PiPHP/GPIO library via Composer:

mkdir phpbutton
composer require piphp/gpio

Now create a file named ledtest.php with the following contents:

<?php

require __DIR__ . '/vendor/autoload.php';

use PiPHP\GPIO\GPIO;
use PiPHP\GPIO\Pin\InputPinInterface;

$gpio = new GPIO();

//our button is on pin 21
$button = $gpio->getInputPin(21);
//this will set interrupts for both up (click) and down (release)
$button->setEdge(InputPinInterface::EDGE_BOTH);
// Create an interrupt watcher
$interruptWatcher = $gpio->createWatcher();

/**
 * we will treat each LED separately for this example.
 * now we are gonna set the RGB LED (pins 13, 12 and 19 respectively) to off, using a little self-contained class
 * created for this example (check the bottom of the file)
 */
LED::off(13);
LED::off(12);
LED::off(19);

// Register a callback to be triggered on pin interrupts
$interruptWatcher->register($button, function (InputPinInterface $pin, $value) {
echo 'Pin ' . $pin->getNumber() . ' changed to: ' . $value . PHP_EOL;
    if ($value) {
        // for testing, we will be using the RED LED. it should light up when the button is pressed.
        LED::on(13);
    } else {
        LED::off(13);
    }

// Returning false will make the watcher return false immediately
return true;
});

// Watch for interrupts, timeout after 5000ms (5 seconds)
while ($interruptWatcher->watch(5000));

/*
 * this class makes life a bit easier for working inside the anonymous function.
 */
class LED {
    protected $ledR;
    protected $ledG;
    protected $ledB;

    public static function on($pin)
    {
        self::getGPIO($pin)->setValue(InputPinInterface::VALUE_HIGH);
    }

    public static function off($pin)
    {
        self::getGPIO($pin)->setValue(InputPinInterface::VALUE_LOW);
    }

    public static function getGPIO($pin)
    {
        return (new GPIO())->getOutputPin($pin);
    }
}

Run the code with: php ledtest.php . It should block the terminal waiting for input. Press the button to see the magic happening!

You should see a red light turn on whenever the button is pressed. This code is for a common cathode RGB LED – if you are using a common anode RGB LED, you will probably see an inverted result (LED is red and goes off when pressed). In this case, you can simply invert the values (LOW for ON and HIGH for OFF).

From this point you can build a LOT of stuff that is fired when you click the button. To keep things simple for this tutorial, we’re just gonna make a request to a URL whenever the button is clicked. The LED will turn GREEN if the request was successful, or RED otherwise. To deal with the requests, we’re gonna use the Composer library Guzzle.

Step 3: Work the Code

We’re now going to create a better structure to put the code on, so it gets easier to extend it and customize to anyone’s needs.  To keep things to a minimal here, we’re gonna use plain PHP powered by Composer.

Note on frameworks: At this point, if you’d like, you could go for a cli PHP framework like Laravel Zero – tested and approved, it installs and runs easily on the Pi Zero. However, you’re gonna need PHP 7.1 for that. You can also run Symfony apps with both PHP 7.0 and 7.1, but it seems impossible to install it through the Pi itself (Composer memory issues). In this case you can install everything from your dev machine and rsync the stuff back to the Pi. I didn’t test Laravel yet except for the “Zero” version, but assuming you have PHP 7.1 you should be fine with that one too.

We’ll require another Composer library to install Guzzle, an HTTP wrapper/client. From the project’s directory, run:

composer require guzzlehttp/guzzle

Now we’ll update the composer.json file to include an autoload definition that will automatically load our custom classes, using psr-4. This is how the composer.json file should look like, after adding the autoload:

{
    "require": {
        "piphp/gpio": "^0.3.3",
        "guzzlehttp/guzzle": "^6.3"
    },
    "autoload": {
	 "psr-4": {
              "PHPButton\\": "src/"
	 }
    }
}

Next, create the src directory and create a new file named LED.php inside it. The contents are gonna be almost the same of what we had before in the test.php file, but with a few refinements, like checking for a common anode and defining more color options:

<?php
/**
 * This class controls an RGB LED with static methods. It works with both common anode and common cathode RGB LEDs
 */
namespace PHPButton;

use PiPHP\GPIO\GPIO;

class LED
{
    const PIN_RED = 13;
    const PIN_GREEN = 19;
    const PIN_BLUE = 12;

    /** if common anode set to true */
    public static $COMMON_ANODE = false;

    public static $COLOR_RED = [ 1, 0, 0 ];
    public static $COLOR_GREEN = [ 0, 1, 0 ];
    public static $COLOR_BLUE = [ 0, 0, 1 ];
    public static $COLOR_YELLOW = [ 1, 1, 0];
    public static $COLOR_WHITE = [ 1, 1, 1];

    public static function setColor(array $color)
    {
        self::on(self::PIN_RED, $color[0]);
        self::on(self::PIN_GREEN, $color[1]);
        self::on(self::PIN_BLUE, $color[2]);
    }

    public static function on($pin, $value = 1)
    {
        // if common anode, we invert the value
        self::getGPIO($pin)->setValue(self::$COMMON_ANODE ? !$value : $value);
    }

    public static function off($pin = 0)
    {
        // if common anode, we invert the value
        $offvalue = self::$COMMON_ANODE ? 0 : 1;

        if (!$pin) {
            //if not set, turns all off
            self::getGPIO(self::PIN_RED)->setValue($offvalue);
            self::getGPIO(self::PIN_GREEN)->setValue($offvalue);
            self::getGPIO(self::PIN_BLUE)->setValue($offvalue);
        } else {
            self::getGPIO($pin)->setValue($offvalue);
        }
    }

    public static function getGPIO($pin)
    {
        return (new GPIO())->getOutputPin($pin);
    }
}

To make the Request using static methods, we’re gonna create a little “Request” helper class. This is where you should define the URL you want to fire! The natural place for methods that will further manipulate the URL generation, in case you want to send a payload within the request:

<?php

namespace PHPButton;

use GuzzleHttp\Client;

class Request
{
    public static $URL = 'http://codingmama.io';

    public static function send()
    {
        $response = self::getClient()->get(self::$URL);

        return $response->getStatusCode();
    }

    public static function getClient()
    {
        return new Client();
    }
}

Finally, we’ll have the cli script button.php, which will connect all the pieces together. Basically, a refined version of the old test.php :

<?php

require __DIR__ . '/vendor/autoload.php';

use PiPHP\GPIO\GPIO;
use PiPHP\GPIO\Pin\InputPinInterface;
use PHPButton\LED;
use PHPButton\Request;

//initialize LED
LED::off();
LED::setColor(LED::$COLOR_BLUE);

//set up button
$gpio = new GPIO();
$button = $gpio->getInputPin(21);
$button->setEdge(InputPinInterface::EDGE_RISING);
$interruptWatcher = $gpio->createWatcher();

// Register a callback to be triggered on pin interrupts
$interruptWatcher->register($button, function (InputPinInterface $pin, $value) {
    if ($value) {
        //click
        LED::setColor(LED::$COLOR_WHITE);
        //now makes the request
        echo "Button clicked, Now making the request...";
        LED::setColor(LED::$COLOR_YELLOW);
        $code = Request::send();
        echo "Response received: $code";

        if ($code == 200) {
            LED::setColor(LED::$COLOR_GREEN);
        } else {
            LED::setColor(LED::$COLOR_RED);
        }
    }

// Returning false will make the watcher return false immediately
    return true;
});

// Watch for interrupts, timeout after 5000ms (5 seconds)
while ($interruptWatcher->watch(5000));

This is how your directory structure should look like:

.
|-- button.php
|-- composer.json
|-- composer.lock
|-- src
|   |-- LED.php
|   `-- Request.php
|-- test.php
`-- vendor
    |-- autoload.php
    |-- composer
    |-- guzzlehttp
    |-- piphp
    `-- psr

Run the script with:

php button.php

The LED should start in blue. When the button is clicked, it turns white really quick and then yellow right when the request is made. If response was 200, it goes green, otherwise it goes red. It’s a funny little “is-my-site-online” or “are-we-offline” testing tool at least 🙂

What from here?

Well, the sky is the limit! But seriously… think of this button as a boilerplate where you can include other things. But if you want to work with more complex components, you should have a look at this other PHP library: https://github.com/calcinai/phpi . You’ll need to install a PHP extension, but this library supports PWM and SPI, which will open up your possibilities a whole lot. It will be much easier to work with Arduino-compatible stuff! Disclaimer: I didn’t test this library yet, but it’s promising and I will certainly try it out very soon. I’ll update this post when I have done that.

Hope you enjoyed, and if you have questions or suggestions feel free to leave a comment. Cheers \,,/

Leave a Reply

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