Skip to content

Instantly share code, notes, and snippets.

@csquared
Last active April 29, 2019 12:59
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save csquared/4341720 to your computer and use it in GitHub Desktop.
Save csquared/4341720 to your computer and use it in GitHub Desktop.
Heroku Status Lights Monitor - Arduino Software
/*
Heroku Office Status Monitor
What it is: Arduino + Ethernet Shield
What it does: Networked device that provides status monitoring.
Components:
- Status site monitor
HTTP GET to http://outage-lights.herokuapp.com/status to consume current Heroku Platform status.
Go to http://outage-lights.herokuapp.com/ to see if this system is currently working.
- Local Override
A simple web server that turns pin 8 on when it recieves
a GET request to `/on` and turns that pin off when
it receives a GET request to `/off`.
- Trigger Failure when unable to connect to the web.
by Chris Continanza
*/
#include <SPI.h>
#include <Ethernet.h>
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(10,10,10,102);
//Heroku's Public raw IP endpoint FTW
IPAddress status_server(174,129,212,2);
int heartbeat_port = 80;
/* Deprectated: this was used when status and hearbeat were
* separate endonpoints.
int heartbeat_delay_millis = 5000;
int heartbeat_tolerance = 1000;
int last_heartbeat = 0;
*/
int status_delay_millis = 5000;
int status_tolerance = 1000;
int last_status = 0;
int http_failures_limit = 25;
boolean http_on = false;
boolean status_on = false;
int http_failures = 0;
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
int LED = 8;
void setup()
{
pinMode(LED, OUTPUT);
// open the serial port
Serial.begin(9600);
/*
// Not using DHCP so we have a static connection
// start the Ethernet connection:
Uncomment this block to use DHCP.
Serial.println("Trying to get an IP address using DHCP");
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
}
*/
// connect w. static ip - this is assigned at the router
// and makes connecting to the manual override easier.
Ethernet.begin(mac, ip);
// print your local IP address to Serial for debugging.
Serial.print("My IP address: ");
IPAddress my_ip = Ethernet.localIP();
for (byte thisByte = 0; thisByte < 4; thisByte++) {
// print the value of each byte of the IP address:
Serial.print(my_ip[thisByte], DEC);
Serial.print(".");
}
Serial.println();
// start listening for clients
server.begin();
}
/* HTTP Helper method
takes an EthernetClient object and returns a String.
it reads the next HTTP Response from the client one byte at a time.
*/
String readHTTPResponse(EthernetClient _client) {
// an http request ends with a blank line
boolean currentLineIsBlank = true;
boolean httpBody = false;
//string for fetching data from address
String httpRequest = "";
while (_client.connected()) {
if (_client.available()) {
char c = _client.read();
if(httpBody){
httpRequest.concat(c);
}
if (c == '\n' && httpBody){
return httpRequest;
}
if (c == '\n' && currentLineIsBlank) {
httpBody = true;
}
if (c == '\n') {
// you're starting a new lineu
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
}
/* HTTP Helper method
takes an EthernetClient object and returns a String.
it reads the next HTTP Request from the client one byte at a time.
*/
String readHTTPRequest(EthernetClient _client) {
// an http request ends with a blank line
boolean currentLineIsBlank = true;
//string for fetching data from address
String httpRequest = "";
while (_client.connected()) {
if (_client.available()) {
char c = _client.read();
httpRequest.concat(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
return httpRequest;
}
if (c == '\n') {
// you're starting a new lineu
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
}
/* Application loop
*/
void loop()
{
int time = millis();
if(status_on || http_on || http_failures > http_failures_limit){
digitalWrite(LED, HIGH); // set the LED on
}
else{
digitalWrite(LED, LOW); // set the LED off
}
//some delay logic
if((time % status_delay_millis < status_tolerance) &&
(time - last_status > status_delay_millis)){
last_status = time;
/* fire off a GET request to status */
EthernetClient status_client;
status_on = false;
if (status_client.connect(status_server, 80)) {
http_failures = 0;
Serial.println("connected to status");
// Make a HTTP request:
status_client.println("GET /status HTTP/1.0");
status_client.println("Host: outage-lights.herokuapp.com");
status_client.println("Authorization: Basic ---------------");
status_client.println();
String response = readHTTPResponse(status_client);
Serial.println(response);
Serial.println(response.indexOf("red"));
// If its red, turn the switch on.
// could probably make this my own response...
if(response.indexOf("red") == -1){
Serial.println("Status clear - LED OFF");
}
else {
Serial.println("Status red! - LED ON");
status_on = true;
}
}
else {
//count failures cus you didn't get a connection to the server
http_failures++;
Serial.println("connection to status failed");
}
//make sure you write all those bytes.
status_client.flush();
//aaaaaand give it some time
delay(10);
//cleanup
status_client.stop();
}
// Check if an HTTP request came in.
EthernetClient client = server.available();
if (client) {
String httpRequest = readHTTPRequest(client);
Serial.print(httpRequest);
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
//send an HTML response
if(httpRequest.startsWith("GET /on")){
Serial.println("HTTP Request - LED ON");
client.print("<h1>Outage Lights On</h1>");
http_on = true;
}
else if(httpRequest.startsWith("GET /off")){
Serial.println("HTTP Request - LED OFF");
client.print("<h1>Outage Lights Off</h1>");
http_on = false;
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
}
}
/*
Deprecated: heartbeat is assumed when GET goes to /status
//send the Heartbet request for monitoring.
EthernetClient heartbeat;
//delay logic
if((time % heartbeat_delay_millis < heartbeat_tolerance) &&
(time - last_heartbeat > heartbeat_delay_millis)){
Serial.println("heartbeat");
last_heartbeat = time;
// connect to Heroku via direct IP connection
// writing HTTP packet to the Socket like a boss
if (heartbeat.connect(heartbeat_server, heartbeat_port)) {
Serial.println("heartbeat connected");
http_failures = 0;
// Make an HTTP request:
heartbeat.println("POST /heartbeat HTTP/1.0");
heartbeat.println("Host: outage-lights-heartbeat.herokuapp.com");
heartbeat.println("Content-Length: 0");
heartbeat.println("Authorization: Basic -�-------------");
heartbeat.println();
heartbeat.println();
Serial.println("heartbeat sent");
}
else {
//you didn't get a connection to the server:
Serial.println("heartbeat connection failed");
http_failures++;
}
//flush and clean up after yourself
heartbeat.flush();
delay(50);
heartbeat.stop();
}
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment