Web interface for Raspberry-pi GPIO

February 13, 2019

This post is about building a service running on a RPi3 with a web page for interacting with the digital pins, namely turning a led on and off. It is meant to be a showcase of the potential of my CRut framework project, developed alongside to PeerStreamer-ng.

The final result is gonna be a web page with two buttons, on the pressing of which a led connected to the RPi board will change state. To this end we combine two different projects, wiringPi, a library for GPIO interaction and CRut a framework for building web applications in C.

GPIO setup

On Raspbian, we can install wiringPi with

sudo apt install wiringpi

We are gonna use and connect only one pin of the GPIO. This pin must be connected to the led circuit composed of a resistance and the led itself. We can have a look of the available GPIO pins of the RPi3 bord online.

The following is the resulting circuit (I picked pin 40, which becomes 29 according to wiringPi numbering). Raspberry Pi circuit.

Back-end

We need to design our ReST API, I opted in for the easiest choice, one single resource alert_led whose state can be UPDATEd with a variable called state and values on,off. Formally, our interface consists of the HTTP call:

UPDATE hostname/alert_led

To implement it in CRut we need the following code; first we need to declare the HTTP route:

// src/routes.c
uint8_t load_path_handlers(struct router *r)
{
	uint8_t res = 0;
	res |= router_add_route(r, "UPDATE", "^[/]+alert_led$", alert_led);

	return res;
}

Then we can define our path handler, alert_led:

// src/path_handlers.c
#include<wiringPi.h>

void alert_led(struct mg_connection *nc, struct http_message *hm)
{
	char state[80];
	int8_t res = -1;


	mg_get_http_var(&hm->body, "state", state, 79);
	info("UPDATE for alert LED\n");

	if (strncmp(state, "on", 79) == 0)
	{
		digitalWrite(ALERT_LED, HIGH);
		res = 0;
	}
	else if (strncmp(state, "off", 79) == 0)
	{
		digitalWrite(ALERT_LED, LOW);
		res = 0;
	}

	if (res == 0)
		mg_http_short_answer(nc, 200);
	else
		mg_http_short_answer(nc, 400);
}

Where ALERT_LED is a constant defined in context.h. Don’t forget to declare the alert_led method in the path_handler method.

Finally, we need to add wiringPi initialization statements in the main file:

// crut.c
#include<wiringPi.h>

@@ -141,6 +142,9 @@ void init(struct context *c, int argc, char **argv)
 
                c->mongoose_srv = (struct mg_mgr*) malloc(sizeof(struct mg_mgr));
                mg_mgr_init(c->mongoose_srv, c);
+
+               wiringPiSetup();
+               pinMode(ALERT_LED, OUTPUT);
        }
 }

Et voilà, the back-end part is done!

Now we can compile and run it with:

make
./crut

It is now possible to turn the led on/off with, e.g.,:

$> curl -X UPDATE -d state=on http://localhost:3000/alert_led

Front-end

The front-end is gonna be bare minimal, one html file defining button objects and one JavaScript file defining the corresponding actions.

CRut already provides an index.html page based on Twitter Bootstrap, we now just add a couple of buttons:

<!-- Public/index.html -->
...
<script src="mylib.js"></script> 

...

<div id="control-buttons" class="row center-block text-center" style="padding:50px;" >
	<button type="button" class="btn btn-warning" onclick="turn_led_on()">Turn LED on</button>
	<button type="button" class="btn btn-warning" onclick="turn_led_off()">Turn LED off</button>
</div>

...

For the two JavaScript HTTP calls we use the usual XHTTP object,

function turn_led_on()
{
	var xhttp = new XMLHttpRequest();
	xhttp.open("UPDATE", "/alert_led", true);
	xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	var params = "state=on";
	xhttp.send(params);
}

function turn_led_off()
{
	var xhttp = new XMLHttpRequest();
	xhttp.open("UPDATE", "/alert_led", true);
	xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	var params = "state=off";
	xhttp.send(params);
}

And that’s it! Now the web page should appear something like:

CRut Web UI.