In a recent blog I detailed how I designed a case for a button that people can press to notify the office via Slack that a fresh pot of coffee has been brewed. Now for the fun part, the programming.
This project uses the Particle Photon and the Internet Button. Particle's hardware and development environment makes easy IoT projects like this a breeze. There are three components to the code that we'll need to put together:
- The Slack webook that receives the Particle event and publishes a message to the Slack channel.
- The Particle webhook that receives the event from the photon and forwards it to Slack.
- The Particle firmware that sends the button press event and provides some feedback to the button pusher.
1. Slack Webhook
Slack has an extensive guide for setting up incoming webhooks and a guide for formatting the data you send. You'll just need to take note of the Webhook URL.
2. Particle Webhook
Creating a Particle webhook is much easier since the release of the Particle Dashboard Console. Particle has a great walkthrough for setting up the webhook.. A screenshot of the values I used are below. Replace "your info here" with your Slack Webhook URL from step 1.
The :coffee: emoji is a custom emoji that I added to Slack. Slack has a guide for adding custom emoji here.
3. Photon Firmware
Finally, the code. The first thing I did was create a wrapper class that added functionality to Particle's library. Particle's class is the InternetButton so mine is the CoffeeButton. The CoffeeButton class inherits from InternetButton and adds some cleaner ways of detecting a button press and named variables for each of the buttons.
Important Note: If you are using the Particle Build web IDE adding the include statement #include "InternetButton/InternetButton.h" will not be enough to link to the InternetButton library. You will need to click the libraries button, select the InternetButton library and add it to your project.
CoffeeButton.cpp
#include "application.h"
#include "CoffeeButton.h"
// Count the number of buttons that are currently pressed
uint8_t CoffeeButton::countButtonsOn(void)
{
// Initialize the counter
uint8_t buttons_on = 0;
// Increment for every button pressed
buttons_on += buttonOn(top);
buttons_on += buttonOn(left);
buttons_on += buttonOn(right);
buttons_on += buttonOn(bottom);
// Return the counter
return buttons_on;
}
/* Return 1 if any button is pressed
* Return 0 otherwise
*/
uint8_t CoffeeButton::anyButtonOn(void)
{
if(countButtonsOn())
{
return 1;
}
else
{
return 0;
}
}
// Return 1 if the selected button i is pressed
uint8_t CoffeeButton::buttonOn(uint8_t i){
// Only buttons 4 through 7 are valid
if((i>=4) && (i<=7))
// Use the built in Particle function to read the button state
return !digitalRead(i);
else
return 0;
}
CoffeeButton.h
// This #include statement was automatically added by the Particle IDE.
#include "InternetButton/InternetButton.h"
class CoffeeButton : public InternetButton
{
public:
// Declare constant members for naming the buttons
const uint8_t top = 4;
const uint8_t left = 5;
const uint8_t bottom = 6;
const uint8_t right = 7;
// Expose our class methods
uint8_t countButtonsOn(void);
uint8_t anyButtonOn(void);
uint8_t buttonOn(uint8_t i);
};
The bulk of the code is the coffee.ino file. This code initializes the coffee button and triggers the actions on a button press. The Internet Button has built in Neopixel LEDs and a buzzer so when the button is pressed I had the coffee button play a short jingle and light up a series of lights. It then publishes an event to the Particle server.
coffee.ino
// This #include statement was automatically added by the Particle IDE.
#include "CoffeeButton.h"
#include <string.h>
#define DEBOUNCE_TIME 3000 //3000 ms = 3 s
// b is our button
CoffeeButton b;
unsigned long last_push; // Keep track of the last button push time
uint8_t led_number;
String notes[6] = {"E5", "G5", "E6", "C6", "D6", "G6"}; // A short melody
uint8_t i; // For incrementing
void setup() {
// Initialize the button
b.begin();
//Initialize the debounce time
last_push = millis();
}
void loop() {
//If any button is pressed
if(b.anyButtonOn())
{
//Only allow a button press every 3 seconds
if(millis() > last_push + DEBOUNCE_TIME)
{
// Play a string of notes and light up random colors around the circle.
for(i=0; i<6; i++)
{
b.ledOn(i+1, random(255), random(255), random(255));
b.playNote(notes[i],8);
b.ledOff(i+1);
}
//Publish to the Particle server
Particle.publish("coffee", "Fresh coffee in the kitchen", 60, PRIVATE);
//Update debounce time
last_push = millis();
}
}
}
A more robust application would include additional features like response checking and error handling, but this will get us started for finding the freshest brew. Thanks for reading!
Learn more about DMC's embedded design and IoT solutions.