CoffeePot Checker

The Wemos D1

A while ago I stumbled across these little boards called Wemos D1, and bought a few online (on AliExpress, since that seems to be the cheapest Chinese store out there). Delivery takes a month, but who cares when it's for (near) free.

Insert picture of Wemos here

Since they're the same form factor as an Arduino Uno, you can buy some simple acrylic cases for it, which make it look like this:

Insert picture of Wemos with case here

Next up we add some LEDs. In my first iteration I only added the red one, but with two leds you can do much more!

Insert picture of Wemos with LEDs here

So what does it do? In order to answer that we need a little history lesson. Once upon a time, I was working at this firm which had the most horrible coffee out there. So one of my collegues had this brilliant idea to make his own coffee, and spread it with the team. He was such a good guy... Only issue was that I had to walk over to his desk, disturb him, and ask him if there was some coffee left. But not anymore!

Introducing the CoffeePot Checker:

The CoffeePot Checker is a cheap board, with a Wifi chip and 2 LEDs. It acts as an access point, so everyone can see whether or not there is coffee!

$ curl -vvv http://10.10.10.1/status
* Hostname was NOT found in DNS cache
*   Trying 10.10.10.1...
* Connected to 10.10.10.1 (10.10.10.1) port 80 (#0)
> GET /status HTTP/1.1
> User-Agent: curl/7.37.1
> Host: 10.10.10.1
> Accept: */*
> 
< HTTP/1.1 200 OK  
< Content-Type: text/plain  
< Content-Length: 22  
< Connection: close  
< Access-Control-Allow-Origin: *  
<  
{ "coffee": "false" }
* Closing connection 0

When there's coffee, the one that made the coffee does an HTTP request to http://ip-of-wemos/coffee and just like that, the red LED goes on! And after a few minutes, when the IT guys have had their fix, browse to http://ip-of-wemos/nocoffee and and the red LED goes off.

After a while, people made feature requests. Since I'm mostly working with noise cancelling headphones on, I don't notice it when people are standing behind me trying to get my attention. So we added an orange LED, which can be triggered to flicker on and off three times to get my attention.

Another added feature: when it's time for lunch, the orange LED goes on and stays on until lunchbreak is over. (Right now this is triggered manually whenever we're hungry, but the idea is to put the HTTP request in a cronjob).

The board responds to these 'api' calls:

  • /status -> returns the current coffeestatus in JSON
  • /coffee -> switches on the red LED, switches coffeestatus to true
  • /nocoffee -> switches the red LED off, siwtches cofeestatus to false
  • /lunch -> switches on the orange LED, indicating its time for lunch
  • /lunchdone -> switches off the orange LED, urges you to go back to work
  • /poke -> quickly switches the orange led on and off, three times, in order to get my attention
  • /usage (and every other call) -> returns a simple HTML page with this description
Now on to the good stuff! Let's see some code!!!
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

IPAddress ip(10,10,10,1);  //Node static IP

ESP8266WebServer server(80);

const char *ssid = "CoffeePot Checker"; //Hey, we broadcast our own SSID!

const int orangeled = 12; //refer to the pin diagrams on the Wemos website  
const int redled    = 13;

boolean status = false;  
String response;

// Reply with the usage whenever somebody access something we don't know how to handle
String usage = ""  
"<html><head><title>CoffeePot Checker</title></head>"
"<body>"
"<h1>CoffeePot Checker</h1>"
"<ul>"
"<li>/status     = Returns json document with the current coffeestatus</li>"
"<li>/poke       = Flashes the orange led three times</li>"
"<li>/coffee     = Sets the coffeestatus to true, lights up red led</li>"
"<li>/nocoffee   = Sets the coffeestatus to false, turns off red led</li>"
"<li>/lunch     = Lights the orange led, notifying me that it's time for lunch</li>"
"<li>/lunchdone = Turns off the orange led, notifying me it's time for work again</li>"
"</ul>"
"</body></html>";

void setStatus(boolean value) {  
  status = value;
}

boolean getStatus() {  
  return status;
}

String getStatusAsString() {  
  if (status == true) {
    return "true";
  } else {
    return "false";
  }
}

void handleStatus() {  
  response = "{ \"coffee\": \"";
  response += getStatusAsString();
  response += "\" }\n";
  server.send(200, "text/plain", response);
}

void handlePoke() {  
  server.send(200, "text/plain", "Poke!!!\n");
  for (int i = 0; i < 3; i++) {
    digitalWrite(orangeled, 1);
    delay(250);
    digitalWrite (orangeled, 0);
    delay(250);
  }
}

void handleCoffee() {  
  digitalWrite(redled, 1);
  setStatus(true);
  handleStatus();
}

void handleNoCoffee() {  
  digitalWrite(redled, 0);
  setStatus(false);
  handleStatus();
}

void handleLunch() {  
  digitalWrite(orangeled, 1);
  server.send(200, "text/plain", "I'm on my way!\n");
}

void clearLunch() {  
  digitalWrite(orangeled, 0);
  server.send(200, "text/plain", "Hope you had a nice meal, now get back to work.\n");
}

void handleRoot() {  
  server.send(200, "text/html", usage);
}

void setup(void){  
  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(ip, ip, IPAddress(255, 255, 255, 0));
  WiFi.softAP(ssid);

  pinMode(redled, OUTPUT);
  pinMode(orangeled, OUTPUT);

  server.on("/", handleRoot);
  server.on("/poke", handlePoke);
  server.on("/coffee", handleCoffee);
  server.on("/nocoffee", handleNoCoffee);
  server.on("/status", handleStatus);
  server.on("/lunch", handleLunch);
  server.on("/lunchdone", clearLunch);
  server.onNotFound(handleRoot);

  server.begin();
}

void loop(void){  
  server.handleClient();
}