Introduction: Ashtray Counter

We will be creating a smart connect Ashtray Counter. It will count the cigarettes that fall in and will light up red if the user smokes too much. The max amount that is allowed per day is controlled with a mobile device.

In this Instructable we will go over the wiring, setting up the WiFi, creating feeds with Adafruit and the code to make it all work.

Step 1: What You Need

Software

Hardware

  • 1x Node MCU ESP8266 Buy
  • 7x Jumper Wires Male/Female & Female/Female Buy
  • 1x HC-SR04 (Ultrasonic Range Detector) Buy
  • 1x RGB LED Buy

Other

Step 2: Wire Setup

HC-SR04

TRIGGER ->D1* Note that with our sensor the SIG is split into TRIGGER en ECHO

ECHO -> D2

VCC -> 5V

GND -> GND

LED RGB

GREEN -> D3

RED -> D4

GND -> GND

Step 3: Setup Adafruit

Adafruit will be used to control the Arduino board over the internet. It uses feeds to listen to the data received from the board.

Step1:

Create and account or login link.

Navigate to https://io.adafruit.com/ and on the left click on View AIO Key. Copy this somewhere or note it down.

Step 2:

Navigate to feeds in the left bar and go to Actions -> Create New Feed. Name this feed slider.

Create another one and name this one reset.

Step 3:

Now that we have two feeds where we can record data we are going to create a slider and a button for the feed.

Navigate to Dashboard on the left and create a new Dashboard with Actions -> Create a New Dashboard.

Give it any name you like and press Create.

Step 4:

On the top right click the blue + icon to add a new block. Choose the Slider and mark the checkbox of the feed you named slider.

Give it a name and adjust the min value -> 0 and max value -> 20.

Create another block and choose the Momentary Reset button. As feed check the newday feed.

Give it a name and adjust the press value to 21 and make sure the release value has nothing in it. Because 21 is never used by the slider it will be recognized by the code we will write later on.

Step 4: C0DE - WiFi & Adafruit Setup

Full code summary:

// Adafruit IO Digital Output Example
// Tutorial Link: https://learn.adafruit.com/adafruit-io-basics-digital-output
//
// Adafruit invests time and resources providing this open source code.
// Please support Adafruit and open source hardware by purchasing
// products from Adafruit!
//
// Written by Todd Treece for Adafruit Industries
// Copyright (c) 2016 Adafruit Industries
// Licensed under the MIT license.
//
// All text above must be included in any redistribution.

// This sketch is based on the example sketch from Adafruit IO Digital Output. It's modified for this project.

#include "config.h" // WiFi/hotspot connection

AdafruitIO_Feed *slider = io.feed("slider");
AdafruitIO_Feed *reset = io.feed("reset");

void setup() {
  
  Serial.begin(115200);                       // Serial speed 115200

  while(! Serial);                            // Wait for serial monitor

  Serial.print("Connecting to Adafruit IO");  // Connect to io.adafruit
  io.connect();

  slider->onMessage(handleMessage);           // Message Handler
  reset->onMessage(handleMessage);

  while(io.status() < AIO_CONNECTED) {        // Wait for connection
    Serial.print(".");
    delay(500);
  }

  Serial.println();                           // Print connection status
  Serial.println(io.statusText());

}

void loop() {

  io.run();                                   // Keeps the connection alive

}

void handleMessage(AdafruitIO_Data *data) { 

  int reading = data->toInt();

}

Create a new sketch in Arduino, save it and choose a location where you can easily find it. After you save it there will be a folder with the name you entered with a file sharing the same name. In this folder create a new text file with the name 'config.h'.

In the new sketch you created we are going to include the text file you just created by referencing it with #include "config.h" and reference your Adafruit feed name.

#include "config.h" // WiFi/hotspot connection

AdafruitIO_Feed *slider = io.feed("slider");
AdafruitIO_Feed *reset = io.feed("reset");

Since it's in the same map we can edit the file on the tab next to it.

Paste the code below to 'config.h':

/************************ Adafruit IO Config *******************************/

// visit io.adafruit.com if you need to create an account,
// or if you need your Adafruit IO key.
#define IO_USERNAME    "<ADAFRUIT USERNAME>"
#define IO_KEY         "<ADAFRUIT IO KEY>"

/******************************* WIFI **************************************/

// the AdafruitIO_WiFi client will work with the following boards:
//   - HUZZAH ESP8266 Breakout -> https://www.adafruit.com/products/2471
//   - Feather HUZZAH ESP8266 -> https://www.adafruit.com/products/2821
//   - Feather M0 WiFi -> https://www.adafruit.com/products/3010
//   - Feather WICED -> https://www.adafruit.com/products/3056

#define WIFI_SSID       "<WIFI/HOTSPOT NAME>"
#define WIFI_PASS       "<WIFI PASSWORD>"

// comment out the following two lines if you are using fona or ethernet
#include "AdafruitIO_WiFi.h"
AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS);


/******************************* FONA **************************************/

// the AdafruitIO_FONA client will work with the following boards:
//   - Feather 32u4 FONA -> https://www.adafruit.com/product/3027

// uncomment the following two lines for 32u4 FONA,
// and comment out the AdafruitIO_WiFi client in the WIFI section
// #include "AdafruitIO_FONA.h"
// AdafruitIO_FONA io(IO_USERNAME, IO_KEY);


/**************************** ETHERNET ************************************/

// the AdafruitIO_Ethernet client will work with the following boards:
//   - Ethernet FeatherWing -> https://www.adafruit.com/products/3201

// uncomment the following two lines for ethernet,
// and comment out the AdafruitIO_WiFi client in the WIFI section
// #include "AdafruitIO_Ethernet.h"
// AdafruitIO_Ethernet io(IO_USERNAME, IO_KEY);

Fill in the brackets with your own information.

For example:

#define IO_USERNAME    "Geoffreytn"
#define IO_KEY         "*****************************8b2"
#define WIFI_SSID       "iPhone van Geoffrey"
#define WIFI_PASS       "************"

Don't use stars obviously :)

Back to sketch in the void setup:

  Serial.begin(115200);                       // Serial speed 115200

  while(! Serial);                            // Wait for serial monitor

  Serial.print("Connecting to Adafruit IO");  // Connect to io.adafruit
  io.connect();

  slider->onMessage(handleMessage);           // Message Handler
  reset->onMessage(handleMessage);

  while(io.status() < AIO_CONNECTED) {        // Wait for connection
    Serial.print(".");
    delay(500);
  }

  Serial.println();                           // Print connection status
  Serial.println(io.statusText());

Set your serial baud rate to 115200 in Tools > Upload Speed. This is needed to open the serial monitor for debugging purposes.

  slider->onMessage(handleMessage);           // Message Handler
  reset->onMessage(handleMessage);

These are the names we filled in at the top and the reference to the name of the feed in Adafruit.

In the void loop we will use this line:

io.run();

It will keep the connection alive.

Under the void loop we will create a new function named handleMessage:

void handleMessage(AdafruitIO_Data *data) {

  int reading = data->toInt();

}

We create a variable reading which contains the data that is converted to an Int value.

Step 5: C0DE - HC-SR04 & RGB LED

Now that we have a wifi connection and connected to your Adafruit IO feed we will add code on top of it.

At the top above the void setup add in the new lines:

#include "config.h" // WiFi/hotspot connection

#define trigger D1  // HC-SR04: Trigger
#define echo D2     // HC-SR04: Echo
#define led_g D3    // LED: Green
#define led_r D4    // LED: Red

int maxCounter = 3; // Maximum cigarettes to be counted
int counter = 0;    // Current cigarette count

AdafruitIO_Feed *slider = io.feed("slider");
AdafruitIO_Feed *reset = io.feed("reset");

We are giving names to the digital inputs to make it easier for use to understand for what is connected to that specific input. We also use it for reference later in the code.

The globale variable maxCounter and counter is used for comparison and needs to be accessible as a global variable.

In the void setup:

void setup() {

  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);
  pinMode(led_g, OUTPUT);
  pinMode(led_r, OUTPUT);
  
  Serial.begin(115200);                       // Serial speed 115200

  while(! Serial);                            // Wait for serial monitor

  Serial.print("Connecting to Adafruit IO");  // Connect to io.adafruit
  io.connect();

  slider->onMessage(handleMessage);           // Message Handler
  reset->onMessage(handleMessage);

  while(io.status() < AIO_CONNECTED) {        // Wait for connection
    Serial.print(".");
    delay(500);
  }

  Serial.println();                           // Print connection status
  Serial.println(io.statusText());

}

Here we added pinMode to tell Arduino if it should receive an input or use it as an output. As you can see here we use the names as reference to the pin which makes it easier for us to understand.

In the void loop:

void loop() {

  io.run();  // Keeps the connection alive

  //### HC-SR04 ###//
  long duration, distance;
  digitalWrite(trigger, LOW);
  delayMicroseconds(2);
  digitalWrite(trigger, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigger, LOW);
  duration = pulseIn(echo, HIGH);
  distance = (duration/2) / 29.1;
//  Serial.print("HC-SR04: ");
//  Serial.print(distance);
//  Serial.println(" Centimeters"); // Debug
  delay(100);
  //### HC-SR04 ###//

  if (distance < 8 && counter >= maxCounter) {
    counter++;
    
    Serial.print("Counted cigarettes: ");
    Serial.print(counter);
    Serial.print("/");
    Serial.println(maxCounter);
    
    digitalWrite(led_r, HIGH);
    delay(2000);
    digitalWrite(led_r, LOW);
  } else if (distance < 8 && distance != 0 && counter < maxCounter) {
    counter++;

    Serial.print("Counted cigarettes: ");
    Serial.print(counter);
    Serial.print("/");
    Serial.println(maxCounter);
    
    digitalWrite(led_g, HIGH);
    delay(2000);
    digitalWrite(led_g, LOW);
  }

}

Lets break it down. The code below is for the Ultrasonic Range sensor:

  //### HC-SR04 ###//
  long duration, distance;
  digitalWrite(trigger, LOW);
  delayMicroseconds(2);
  digitalWrite(trigger, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigger, LOW);
  duration = pulseIn(echo, HIGH);
  distance = (duration/2) / 29.1;
//  Serial.print("HC-SR04: ");
//  Serial.print(distance);
//  Serial.println(" Centimeters"); // Debug
  delay(100);
  //### HC-SR04 ###//

The next code below we use IF statements to choose a correct piece of code for each interactions. If the distance is below 8 cm that could mean something triggered it. In this instance we use the range detector as a motion detector.It also checks if the counter variable is bigger then maxCounter.

In practice: Every time a sigaret falls in the ashtray the sensor noticed it with its range and checks if it exceeds the max amount. If it does it shows a red light, if not it shows a green light. Both statements also add the sigaret to the counter with counter++.

  if (distance < 8 && counter >= maxCounter) {
    counter++;
    
    Serial.print("Counted cigarettes: ");
    Serial.print(counter);
    Serial.print("/");
    Serial.println(maxCounter);
    
    digitalWrite(led_r, HIGH);
    delay(2000);
    digitalWrite(led_r, LOW);
  } else if (distance < 8 && distance != 0 && counter < maxCounter) {
    counter++;

    Serial.print("Counted cigarettes: ");
    Serial.print(counter);
    Serial.print("/");
    Serial.println(maxCounter);
    
    digitalWrite(led_g, HIGH);
    delay(2000);
    digitalWrite(led_g, LOW);
  }

In the handleMessage function we add:

void handleMessage(AdafruitIO_Data *data) {

  int reading = data->toInt();

  if (reading == 21) {    // Reset button send the value 21
    counter = 0;

    Serial.println("Cigarette count reset to 0");
  } else {
    Serial.print("Received <- ");
    Serial.println(reading);
    Serial.print("Max cigarettes: ");
    Serial.print(maxCounter);
    
    maxCounter = reading; // Slider adjusts maxCounter

    Serial.print(" -> ");
    Serial.println(maxCounter);
  }

}

First we have to check if the reset button is pressed with if (reading == 21). The number was the value we have given to the reset button when it's pressed.

Otherwise the number received will be from the slider. That will be a number between 0 and 20. Then we pass this number to the maxCounter variable with maxCounter = reading.

Step 6: Hello World!

Congratulations! By now you should have a functioning connected ashtray. If this is not the case check the final code below and compare it with your code

Final code:

// Adafruit IO Digital Output Example
// Tutorial Link: https://learn.adafruit.com/adafruit-io-basics-digital-output
//
// Adafruit invests time and resources providing this open source code.
// Please support Adafruit and open source hardware by purchasing
// products from Adafruit!
//
// Written by Todd Treece for Adafruit Industries
// Copyright (c) 2016 Adafruit Industries
// Licensed under the MIT license.
//
// All text above must be included in any redistribution.

// This sketch is based on the example sketch from Adafruit IO Digital Output. It's modified for this project.

#include "config.h" // WiFi/hotspot connection

#define trigger D1  // HC-SR04: Trigger
#define echo D2     // HC-SR04: Echo
#define led_g D3    // LED: Green
#define led_r D4    // LED: Red

int maxCounter = 3; // Maximum cigarettes to be counted
int counter = 0;    // Current cigarette count

AdafruitIO_Feed *slider = io.feed("slider");
AdafruitIO_Feed *reset = io.feed("reset");

void setup() {

  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);
  pinMode(led_g, OUTPUT);
  pinMode(led_r, OUTPUT);
  
  Serial.begin(115200);                       // Serial speed 115200

  while(! Serial);                            // Wait for serial monitor

  Serial.print("Connecting to Adafruit IO");  // Connect to io.adafruit
  io.connect();

  slider->onMessage(handleMessage);           // Message Handler
  reset->onMessage(handleMessage);

  while(io.status() < AIO_CONNECTED) {        // Wait for connection
    Serial.print(".");
    delay(500);
  }

  Serial.println();                           // Print connection status
  Serial.println(io.statusText());

}

void loop() {

  io.run();  // Keeps the connection alive

  //### HC-SR04 ###//
  long duration, distance;
  digitalWrite(trigger, LOW);
  delayMicroseconds(2);
  digitalWrite(trigger, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigger, LOW);
  duration = pulseIn(echo, HIGH);
  distance = (duration/2) / 29.1;
//  Serial.print("HC-SR04: ");
//  Serial.print(distance);
//  Serial.println(" Centimeters"); // Debug
  delay(100);
  //### HC-SR04 ###//

  if (distance < 8 && counter >= maxCounter) {
    counter++;
    
    Serial.print("Counted cigarettes: ");
    Serial.print(counter);
    Serial.print("/");
    Serial.println(maxCounter);
    
    digitalWrite(led_r, HIGH);
    delay(2000);
    digitalWrite(led_r, LOW);
  } else if (distance < 8 && distance != 0 && counter < maxCounter) {
    counter++;

    Serial.print("Counted cigarettes: ");
    Serial.print(counter);
    Serial.print("/");
    Serial.println(maxCounter);
    
    digitalWrite(led_g, HIGH);
    delay(2000);
    digitalWrite(led_g, LOW);
  }

}

void handleMessage(AdafruitIO_Data *data) { 

  int reading = data->toInt();

  if (reading == 21) {    // Reset button send the value 21
    counter = 0;

    Serial.println("Cigarette count reset to 0");
  } else {
    Serial.print("Received <- ");
    Serial.println(reading);
    Serial.print("Max cigarettes: ");
    Serial.print(maxCounter);
    
    maxCounter = reading; // Slider adjusts maxCounter

    Serial.print(" -> ");
    Serial.println(maxCounter);
  }

}