Last month we showed you how to aggregate requests in your web app so you could periodically ping the server, rather than on every action. Now we show you how to use that data.
LET’S GET SERVING!
So we’re going to kick off right from our HTML package we created (or you downloaded) in Part 2. Using this code, we could hold the content in our JavaScript memory, and then do a faux submit and clear.
There are a few minor changes on the web app side which need to happen to make it do server requests instead of example tricks. However, first you have to consider the data you’re sending and what you’re doing with it on the Arduino side.
For our demonstrations, we’re merely controlling LEDs. However, if your Arduino is checking for the state of a sensor or something similar first, it may need to send a “fail” message and halt the process.
THE BUILD
Parts Required: | Jaycar | ||
---|---|---|---|
1 × Arduino Compatible UNO | XC4410 | ||
1 x Arduino Compatible Ethernet Shield | XC4412 | ||
1 × 10mm Red LED | ZD0200 | ||
1 × 10mm Yellow LED | ZD0210 | ||
1 × 10mm Green LED | ZD0205 | ||
3 x 220Ω 1/4W Resistors* | RR0556 |
* Quantity shown, may be sold in packs. You’ll also need a breadboard and prototyping hardware.
The hardware build for this is very straightforward, with just 3 x LEDs and a few resistors, in addition to the UNO and Ethernet board. We’ll use the same hardware for both demonstrations, since the difference is in the software and how it’s handled.
Follow the fritzing as shown below, taking care with the orientation of the LEDs. We’re using PWM controls to illuminate the LEDs (you’ll see why shortly), which means we are restricted to the pins we can use. We’re using pins 3, 5, and 6, which are PWM enabled. The LEDs all have a common ground. This makes operation and wiring very simple.
TEST CODE
As with any build, when we’re connecting various technologies, it’s useful to know that our wiring is working. A simple missing ground can halt an entire project, and you might go looking at the web app to find out why it’s not working. So we created a simple test sketch to ensure the wiring is correct.
Load iot_server_wiring_text.ino from the Resource section on our website. Compile it onto your UNO. You should see the LEDs illuminate in order of red, yellow, then green. Then they’ll all switch on to full brightness.
If you open serial monitor at 9600 baud, it will also output what it’s doing at each step so you can isolate any issues too.
SEQUENCING THE REQUESTS
With this method, we’re effectively breaking up our aggregated data once again, and submitting it to the Arduino one at a time. Arguably, this is the most powerful method. You can use your Javascript to do the heavy lifting in terms of timing, though you’re somewhat at the mercy of a few factors, namely latency.
While you can have the JavaScript count the seconds and fire off requests as you desire, you lose a certain amount of control because you don’t know precisely how long the server will take to respond. On a local network, this doesn’t really matter as it’ll almost always be negligible.
However, if you’re sending lots of requests and your server is working hard, you might find delays in response times. This can be the case regardless of how you structure your requests, but this unknown response time can throw things out of whack quickly - but only if the timing matters!
The primary advantage here, however, is that we can receive a response from the Arduino in between each request. This is useful because we can ensure each action has taken place before proceeding to the next, and even provide feedback to the web app about the state of the transaction taking place. We’ll do this in serial monitor, but in some scenarios, you’ll want to push this to your web app interface too.
This stepped progression means that you could allow a user to interrupt things while the sequence is running, if there was a potential need. While it’s unlikely we’d need to interrupt LEDs switching on and off, if we had programmed a robot to make a series of moves, and it started running into a wall, this interruptability may become incredibly useful.
Ultimately the biggest challenge with an Arduino web server, which we don’t really have with a regular web server, is the ultra-restricted memory and processing limitations. We usually want to keep as much processing away from the Arduino, which is one of the reasons we’re building a web app in the first place, right?!
THE ARDUINO CODE
Open up the code iot_server_web_app_sequencing.ino from the Resource. This server code integrates the previous installment’s web server code, with a few modifications in line with the LED test we’ve just run.
Our main loop that handles the server requests still looks somewhat recognisable, but we’ve added a few bits of code to figure out what’s coming in as the request.
We’ve decided to send standard response headers for any case.
// send standard response headers, so our browser knows what to do
client.println("HTTP/1.1 200 OK");
client.println("Access-Control-Allow-Origin: *");
This prevents us from confusing the web browser since if there’s no response sent, it will throw a nasty “no response” error.
In order to work with the URL request inside an Arduino, we need to assess the incoming query again. Unfortunately, in an Arduino there’s no efficient way to reliably achieve this. You can mess about trying to analyse the string, but it starts to run into heavy memory territory, so we’re going to keep it simple and define actions for all six possibilities.
if (strstr(linebuf, "GET /red1") > 0) {
fadeIn(red);
}
if (strstr(linebuf, "GET /red0") > 0) {
fadeOut(red);
}
if (strstr(linebuf, "GET /yel1") > 0) {
fadeIn(yel);
}
if (strstr(linebuf, "GET /yel0") > 0) {
fadeOut(yel);
}
if (strstr(linebuf, "GET /grn1") > 0) {
fadeIn(grn);
}
if (strstr(linebuf, "GET /grn0") > 0) {
fadeOut(grn);
}
While this seems terribly inefficient, it’s not too bad. We’ve sent our response headers already. We then pass the action on to our fadeIn and fadeOut functions accordingly.
We attempted a handful of methods to do this more programmatically, but ended up with more code than it took to implement these simple, fast executing actions. If we had 100 LEDs to control, then the efficiency would likely shift again.
In reality, this project is more focused on the web app anyway. If we need a more complex server, arguably the Arduino environment is not the best route, and using Python on a more powerful chip is probably advisable.
As it is, we’re using 50% of the program memory and 45% of the dynamic memory - it adds up quickly (though admittedly most of it goes in the libraries).
TESTING THE URL RESPONSE
You can easily test the response of your server, but visiting the URLs we have set up in your browser.
Simply visit http://your_ip/red1 and the red LED should fade in. Try /red0, and the red LED should fade out nicely too.
You won’t see any text in the browser window, as we haven’t told our Arduino to provide any. However, we do output all the actions to Serial Monitor.
THE WEB APP CODE
Now it’s time to get our web app to iterate through our array we’ve built.
Open up the HTML package from the digital resources. You want to open the index.html file and enter the IP address provided in Serial Monitor from your Arduino. It may already be there in the cache from last time if you followed parts 1 and 2, but ensure it hasn’t changed.
All the modifications in the web app between Part 2 and Part 3, occur in the JavaScript file. Though we did change the colours of the buttons to red, yellow, green, rather than red, green, blue.
Previously we would simply aggregate the data and output to the JavaScript console so we could see it. Now we simply modify that code to do something more fun!
if (press != ‘submit’) {
// we push the details of the button pushed
// to the array storing our sequence
queryCache.push(e.target.dataset[‘id’]);
console.log(queryCache);
} else {
// our submit button is being pushed
// this is where we would push our
// data to the server
var url = "http://" + ip;
// the data has been submitted, clear the
// cache to start the next sequence
queryCache = [];
console.log(‘Submitting and emptying ‘ + queryCache);
}
The aggregation function in the first part of the code can stay as it is. It’s collecting the colour and the on or off action, which conveniently matches the URL we need to target.
All of the changes will be after the “} else {“ which is our handling of submission. This will be in the form of a loop, to break down the array, and an AJAX call within that loop.
Our new code looks something like this:
}
else {
// our submit button is being pushed
// this is where we would push data to the server
executeAjaxCall();
}
Looks a little too simple, right? Absolutely. That’s because we’ve had to move the heavy lifting to a new function, this is so we can ensure things happen in sequence. We could simply loop the queryCache array and fire off all of the requests at once, but there’s one critical piece of the puzzle; timing.
One of the reasons we changed the LED transitions from an on/off to a fade, was to have some sort of requirement for timing. There’s no point us firing off all of our queued requests quickly without ensuring things have had time to run on the server (that is, our LED fading in or out). Otherwise, you have requests on top of each other, often requesting opposing actions.
function executeAjaxCall() {
var url = "http://" + ip + ‘/’;
$.ajax({
type: ‘GET’,
url: url + queryCache[0],
success: function() {
// destroy the element we just processed
queryCache.shift();
// if there’s more to do, do it
if (queryCache.length > 0) {
executeAjaxCall();
}
else {
// we’re all done!
queryCache = [];
console.log(‘All actions submitted’);
}
},
error: function(e) {
console.log(‘Error - something happened’);
}
});
}
For this reason, our “submit” action calls a new function, we’ve called “executeAjaxCall”. The main reason we’ve pulled this code to a new function is so we can call it recursively. That means the function actually calls itself under certain circumstances.
In this case, once the AJAX call has received a valid response, it decides what to do. First, it removes the element and takes a look at the queryCache array to see if there’s more to do. If there is still contents in the array, it calls the executeAjaxCall function again, using the next available request in the array.
One interesting aspect of this approach is, you can actually add more actions to the “queue”, as long as it’s still actively being processed. if it has already finished, you’ll have to press submit to kick it off again once there’s something in the queue.
Check out the image from the console. You can see how the array is growing, but then suddenly reduces in size, before growing again. This is because while the initial sequence had finished, I pushed more buttons which added to the request queue. Because the executeAjaxCall function is recursive, when it looked at queryCache, it found more things to do, so kept going. Try it yourself!
We only have a 1-second fade here on each request, but imagine if you had a 1-hour action taking place. You could queue up hours worth of actions, and if they weren’t finished running but you wanted to add more, you can simply make the requests and they’ll get processed when the items already in the queue have successfully been processed!
WHERE TO FROM HERE?
We have a powerful sequence working well now, but what if the server wants to provide feedback on the state?
Next month, we’ll cover various server responses and handling, for even better interactivity.