Arduino365 Introduction

By:
Posted: 12th April 2019
Category: Arduino
Comments: 0

This is for anyone who is serious about keeping their project(s) running 24/7/365 using the Arduino platform. This is obviously not aimed at hardcode industrial deployments. If you require that kind of stuff it is obvious that Arduino is not and should not be your choice - just saying. I got quite excited when I have received my Elegoo arduino uno clones and decided to see how they stack up against 24/7 use. So.... after a few hours I had a working "prototype". Here I will try to give an overview what I have done and what is the goal for this project - which will actually be a series of blog posts with some ideas how to keep your project running all year round + I will be twitting the uptime on regular-ish basis (and other related stuff).

My mindset for this project was: Mitigate everything that can cause potential issues in the long run.

The finished setup v1.0 looks like this:


Please be aware that this is a learning experience and I have no doubt that there will be some refinement of my methods / hardware used as I go along.

Power
I have connected the electronics to an Uninterrupted Power Supply (could be overkill but I want it to run 365 right?). This should deliver a stable power output and protect everything from surges, outages etc The arduino power supply... I have used a spare TPLINK brick (9v@0.85A) that I think will be good enough for the task (those things never die). Will see how it goes.

Watchdog
Here the simplest of them all with a little twist. I have a wire in the RESET pin that will be triggered to restart the board via a digital pin (green cable in this case) - all of this will be written inside the ISR(WDT_vect) function. I will be using the longest interval that is available to the circuit (8 seconds). When you will see the code you will understand :)

Brown-out Detection
There is one build-in to the uno. I have "burned" the fuse to activate at 4.3V - apparently this is the smartest way to go about it (time will tell tho...). By default it comes at 2.7V which doesn't seem to be working great if your uno is set to run at 16MHz (also default as far as I am aware). I will be testing this when I get my buck converters... that will be fun !

Software
This could be subjective, however I have found that using "threads" in my projects gave me the ability to utilise the watchdog in a more structured way. I am using this library to achieve this. In my experiments so far it has been reliable. However there could be a better implementation of this somewhere. Entire source code is provided at the bottom of the page.

Case
This one has nothing to do with uptime obviously. However I do like when the electronics are kept in a tidy manner because I really think that breadboards look messy and not ideal for deployment in the wild. For this I have designed my own case. It holds the arduino uno, the ethernet shield and the passive POE module. It got holes for screws so I can attach it to most surfaces.


What does it do?
The project itself is very simplistic. It is running a web server that will return the uptime of the arduino. At the moment it is : 14:01:06:56 (DD:HH:MM:SS). I was thinking to add a sensor or two but this is my first attempt and I did not want to add any more variables to avoid skewing my results. I could potentially do that at a later stage....

What next?
Keep testing, applying modifications and updating the people who are interested in keeping their projects running 365. I understand not all people have such requirement. But for those who do I will try to give them the best guidance I can (I am learning here as well). Keep in mind that it is a prototyping platform (arduino) at the end of the day.. however I wanna see how far can I push it.

Hope this helps!

#include <Thread.h>
#include <ThreadController.h>

// Watchdog library !
#include <avr/wdt.h>

#include <SPI.h>
#include <Ethernet.h>

int resetPin = 9;
boolean reading
= false;
String HTTPget = "";

byte mac
[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //ethernet shield mac address

byte ip
[] = {
192, 168, 7, 150 }; // arduino IP in lan

byte gateway
[] = {
192, 168, 7, 1 }; // internet access via router

byte subnet
[] = {
255, 255, 255, 0 }; //subnet mask

// (port 80 is default for HTTP):
EthernetServer server
(80);

// ThreadController that will controll all threads
ThreadController controll
= ThreadController();

//My Thread (as a pointer)
Thread
* myWatchdogThread = new Thread();

// callback for watchdog reset Thread...
void watchdogReset()
{
wdt_reset
(); // reset the WDT timer
}

// When watchdog kicks it will run whatever is in here + do a normal watchdog reset
// just to be on the safe side of things... That is if it will even get there!
ISR
(WDT_vect)
{
digitalWrite
(resetPin, LOW); // hit the reset pin hard !
// for some reason... cable is out ? => normal reset
wdt_enable
(WDTO_15MS);
}

void setup()
{

digitalWrite
(resetPin, HIGH); // so we don't end up in an ever lasting loop
pinMode
(resetPin, OUTPUT);

wdt_reset
(); // reset the WDT timer
wdt_disable
();

// start the Ethernet connection and the server:
Ethernet
.begin(mac, ip, gateway, gateway, subnet);
server
.begin();

// Start the watchdog - 8 seconds !
cli
(); // disable all interrupts

MCUSR
&= ~(1<<WDRF);

// Enter Watchdog Configuration mode:
WDTCSR
= (1<<WDCE) | (1<<WDE);

// Set Watchdog settings: interrupt enable, 8 second timeout !
// To enable an interrupt and reset mode just add this " | (1<<WDE) "
WDTCSR
= (1<<WDIE) | 1<<WDP0 | 1<<WDP3 | (1<<WDE);

sei
();

// Configure myWatchdogThread
myWatchdogThread
->onRun(watchdogReset);
myWatchdogThread
->setInterval(6000); // do the watchdog reset every 6 seconds ! The watchdog is set to 8 seconds so this should work just fine

// Adds the WatchDog Reset Thread !
controll
.add(myWatchdogThread);
}


void loop(){
// run ThreadController
// this will check every thread inside ThreadController,
// if it should run. If yes, he will run it;
controll
.run();

// Rest of my code... Ethernet Web Server that returns uptime only !

// listen for incoming clients
EthernetClient client
= server.available();

if (client)
{
// send http repsonse header
client
.println("HTTP/1.1 200 OK");
client
.println("Content-Type: text/html");
client
.println("Access-Control-Allow-Origin: *");
client
.println();
// process request.
processClient
(client);
}

}

void processClient(EthernetClient client)
{
// http request will end with a blank line
boolean lineIsBlank
= true;

while (client.connected())
{
if (client.available())
{

char c = client.read();

if(reading && c == ' ') reading = false;
if(c == '?') reading = true; // ? in GET request was found, start reading the info

//check that we are reading, and ignore the '?' in the URL, then append the get parameter into a single string
if(reading && c != '?') HTTPget += c;

if (c == '\n' && lineIsBlank) break;

if (c == '\n')
{
lineIsBlank
= true;
}
else if (c != '\r')
{
lineIsBlank
= false;
}
}
}


if (HTTPget == "uptime")
{
// First... Let me check when was the last reading done...
unsigned long currentMillis = millis();
unsigned long seconds = currentMillis / 1000;
int days = seconds / 86400;
seconds
%= 86400;
byte hours
= seconds / 3600;
seconds
%= 3600;
byte minutes
= seconds / 60;
seconds
%= 60;
String hString = String(hours);
String mString = String(minutes);
String sString = String(seconds);

if (hours < 10 ) { hString = "0" + String(hours); }

if (minutes < 10 ) { mString = "0" + String(minutes); }

if (seconds < 10 ) { sString = "0" + String(seconds); }

HTTPget
= String(days) + ":" + String(hString) + ":" + String(mString) + ":" + String(sString);
}

client
.print(HTTPget);
delay
(1); // give the web browser a moment to receive
client
.stop(); // close connection
HTTPget
= ""; // clear out the get param we saved
}

Hey, like this? Why not share it with a buddy?