Skip to content

Instantly share code, notes, and snippets.

@mager
Last active November 5, 2022 08:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mager/c827e7a5e0e0c370b247 to your computer and use it in GitHub Desktop.
Save mager/c827e7a5e0e0c370b247 to your computer and use it in GitHub Desktop.
Smart Clapper Arduino sketch
/*
* SmartThings Clapper
* Author: Gilbert Chan
* Update: 10/18/14
* Contributors: Manoj Kunthu, Andrew Mager
*/
#include <SoftwareSerial.h>
#include <SmartThings.h>
#define PIN_THING_RX 3
#define PIN_THING_TX 2
SmartThingsCallout_t messageCallout; // call out function forward decalaration
SmartThings smartthing(PIN_THING_RX, PIN_THING_TX, messageCallout); // constructor
void initialize();
void runDetector();
boolean clapDetected();
int detectClaps(int numClaps);
void indicateClaps();
void readMic();
void printStats();
int ledPin = 13;
bool isDebugEnabled; // enable or disable debug in this example
int stateLED; // state to track last set value of LED
/*-----------------------------
* Variable Declarations
*-----------------------------*/
int TOTAL_CLAPS_TO_DETECT = 2; //The number of claps detected before output is toggled
int offset = 160; // The point above average that the clap is detected
int CLAP_TIME = 4000; // The time allowed between each clap
int sensorValue = 0; //the value read through mic
int toggleOutput = -1;
int SIZE = 3;
int buffer[3];
int loopIteration = 0;
int average = 0;
int total = 0;
//BOARD INPUT MIC
const int inPin0 = A5;
//BOARD OUTPUT SIGNALS
const int out = 10, readyPin = 9;
//CLAP STATE CONSTANTS
const int FINAL_DETECTED = 0, LOST_CONTINUITY = 1, CLAP_NOT_DETECTED = 2;
void setup() {
// setup default state of global variables
isDebugEnabled = true;
stateLED = 0; // matches state of hardware pin set below
// setup hardware pins
pinMode(ledPin, OUTPUT); // define PIN_LED as an output
digitalWrite(ledPin, LOW); // set value to LOW (off) to match stateLED=0
if (isDebugEnabled) { // setup debug serial port
Serial.begin(9600); // setup serial with a baud rate of 9600
Serial.println("setup.."); // print out 'setup..' on start
}
//direct representation of the light bulb that toggles on/off
pinMode(out, OUTPUT);
//once initialize() runs the ready pin turns on
pinMode(readyPin, OUTPUT);
}
void loop() {
smartthing.run();
initialize();
runDetector();
}
/**
* Purpose: Prepares the buffer to recognize ambient noise levels in room.
*/
void initialize() {
loopIteration = 0;
total = 0;
average =0;
digitalWrite(out, LOW);
smartthing.shieldSetLED(0, 0, 0);
for(int i = 0; i < SIZE; i++) {
readMic();
buffer[i] = sensorValue;
total = total + sensorValue;
average = (total/(i+1));
Serial.print("INIT - AVE: ");
Serial.print(average);
Serial.print(" Total: ");
Serial.print(total);
Serial.print(" Sensor: ");
Serial.print(sensorValue);
Serial.print(" Change: ");
Serial.println(sensorValue-average);
delay(50);
}
digitalWrite(readyPin, HIGH);
}
/**
* Purpose: Runs the detector algorithm. Developers can change the number of claps by adjusting TOTAL_CLAPS_TO_DETECT variable up at the top.
*/
void runDetector() {
while(true) {
int clapState = detectClaps(TOTAL_CLAPS_TO_DETECT);
if(clapState == FINAL_DETECTED || clapState == LOST_CONTINUITY) {
Serial.println("--done--");
indicateClap(0);//turn off any clap indicating lights
}
}
}
/**
* Purpose: Detects the number of claps specified. This method is recursive
*/
int detectClaps(int numClaps) {
int clapNum = numClaps;
//Base Case - if clapNum is 0, then all claps have been accounted.
if(clapNum == 0) {
//the output can now be toggled.
toggleOutput *= -1;
indicateClap(clapNum);
Serial.println("----- Clap Limit Reached - Output Toggled -----");
return FINAL_DETECTED;
}
//Read from mic and update ambient noise levels.
readMic();
total = (total - buffer[loopIteration]) + sensorValue;
average = (total/SIZE);
buffer[loopIteration] = sensorValue;
loopIteration = (loopIteration+1)%SIZE;
if(clapDetected()) {
Serial.print("detectClaps - Claps:");
Serial.println(TOTAL_CLAPS_TO_DETECT + 1 - numClaps);
printStats();
indicateClap(clapNum);
delay(100);
for(int i = 0; i < CLAP_TIME; i++) {
int clapState = detectClaps(clapNum - 1);
if(clapState == FINAL_DETECTED || clapState == LOST_CONTINUITY) {
return clapState;
}
}
return LOST_CONTINUITY;
}
return CLAP_NOT_DETECTED;
}
/**
* Purpose: Turns the LED on appropriately to signal a clap detection.
*/
void indicateClap(int clapNum) {
if(clapNum == 0) {
if(toggleOutput == 1) {
digitalWrite(out, HIGH);
smartthing.send("on"); // send message to cloud
} else {
digitalWrite(out, LOW);
smartthing.send("off"); // send message to cloud
}
smartthing.shieldSetLED(0, 0, 0);
} else if(clapNum == 1) {
smartthing.shieldSetLED(9, 9, 0);
} else if(clapNum == 2) {
smartthing.shieldSetLED(9, 0, 0);
}
delay(110);
}
/**
* Purpose: Prints basic statistics data for more info with sensor readouts and data points.
*/
void printStats() {
Serial.print("--- AVE: ");
Serial.print(average);
Serial.print(" Total: ");
Serial.print(total);
//Serial.print(" iterNum: ");
//Serial.print(loopIteration);
Serial.print(" Sensor: ");
Serial.print(sensorValue);
Serial.print(" Change: ");
Serial.println(sensorValue-average); //This is what I used to determine the 'offset' value
}
/**
* Purpose: A clap is detected when the sensor value is greater than the average plus an offset. The offset might need to be fine tuned for different sound sensors.
*/
boolean clapDetected() {
return sensorValue > average + offset;
}
/**
* Purpose: Reads mic input and stores it in a global variable.
*/
void readMic() {
sensorValue = analogRead(inPin0);
}
void on() {
stateLED = 1; // save state as 1 (on)
digitalWrite(ledPin, HIGH); // turn LED on
smartthing.shieldSetLED(1, 1, 1);
smartthing.send("on"); // send message to cloud
Serial.println("on");
}
void off() {
stateLED = 0; // set state to 0 (off)
digitalWrite(ledPin, LOW); // turn LED off
smartthing.shieldSetLED(0, 0, 0);
smartthing.send("off"); // send message to cloud
Serial.println("off");
}
void messageCallout(String message) {
// if debug is enabled print out the received message
if (isDebugEnabled) {
Serial.print("Received message: '");
Serial.print(message);
Serial.println("' ");
}
// if message contents equals to 'on' then call on() function
// else if message contents equals to 'off' then call off() function
if (message.equals("on")) {
on();
} else if (message.equals("off")) {
off();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment