Amol Disale
Published © GPL3+

Eco - A Smart Garbage Container

An Internet of Things-based smart garbage collection system!

IntermediateFull instructions provided15 hours10,495

Things used in this project

Hardware components

NodeMCU ESP8266 Breakout Board
NodeMCU ESP8266 Breakout Board
Any Esp8266 is good for this project (Like Adafruit Huzzah, SaprkFun Esp8266 Thing, etc.)
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
×1
DS18B20 Digital temperature sensor
×1
General Purpose PCB
×1
USB-A to Micro-USB Cable
USB-A to Micro-USB Cable
×1
Jumper wires (generic)
Jumper wires (generic)
Mostly Male/Female and Male/Male Jumper Wires required
×1

Software apps and online services

ARTIK Cloud for IoT
Samsung ARTIK Cloud for IoT
Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

Pinout Of NodeMCU

Schemtaics of Eco v2.0 in Fritzing

Contains the fritzing file of of Smart Trash Container 2.0 version

Schemtaics of Eco v2.0

Sensor Connection Diagram of (Smart Trash Container 2.0 version)

Pinout of DS18B20 Sensor

Code

DS18B20 Address

Arduino
Finding DS18B20 Digital Temperature sensors's Address to get the temperature
#include <OneWire.h>

OneWire  ds(2);  // Data wire is plugged into GPIOpin 2 on the Esp8266

//Reset the NodeMCU so you can see the output

//As i connected the sensor i got the following output
//Getting the address...
//The address is:	0x28, 0xFF, 0x2B, 0x09, 0x16, 0x15, 0x03, 0x39

void setup(void) {
  Serial.begin(9600);
  getDeviceAddress();
}

void getDeviceAddress(void) {
  byte i;
  byte addr[8];

  Serial.println("");
  Serial.println("Getting the address...\n\r");
  /* initiate a search for the OneWire object we created and read its value into
  addr array we declared above*/
  
  while(ds.search(addr)) {
    Serial.print("The address is:\t");
    //read each byte in the address array
    for( i = 0; i < 8; i++) {
      Serial.print("0x");
      if (addr[i] < 16) {
        Serial.print('0');
      }
      // print each byte in the address array in hex format
      Serial.print(addr[i], HEX);
      if (i < 7) {
        Serial.print(", ");
      }
    }
    // a check to make sure that what we read is correct.
    if ( OneWire::crc8( addr, 7) != addr[7]) {
        Serial.print("CRC is not valid!\n");
        return;
    }
  }
  ds.reset_search();
  return;
}

void loop(void) {
  // do nothing
}

DS18B20 Sensor Interfacing

Arduino
Reading the temperature from the DS18B20 sensor
#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into GPIOpin 2 (i.e.D4) on the NodeMCU Esp8266
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

// Assign the unique addresses of your 1-Wire temp sensors
DeviceAddress insideThermometer = { 0x28, 0xFF, 0x2B, 0x09, 0x16, 0x15, 0x03, 0x39 };
 
float temp_c=0.0;          // Values read from Temperature sensor

void printTemperature(DeviceAddress deviceAddress)
{
    sensors.requestTemperatures();
    temp_c = sensors.getTempC(deviceAddress);
    if (temp_c == -127.00) {
    temp_c=0.0;
    Serial.println("Error getting temperature");
    } 
    else {
    Serial.print("Inside temperature is: ");
    Serial.print(temp_c);
    Serial.print( char(176)); 
    Serial.println("C.");   }
}

void setup(void)
{
  // You can open the Arduino IDE Serial Monitor window to see what the code is doing
  Serial.begin(115200);  // Serial connection from ESP-01 via 3.3v console cable
   // Start up the library
  sensors.begin();
  // set the resolution to 10 bit (good enough?)
  sensors.setResolution(insideThermometer, 12);
}
 
void loop(void)
{
    printTemperature(insideThermometer);
    delay(5000);
} 
 

Ultrasonic Sensor Interfacing

Arduino
Reading the garbage level in the garbage container using Ultrasonic Sensor
int trigPin = 14;    //Trig - Ultrasonic sensor connected to NodeMCU GPIO14 i.e.D5

int echoPin = 12;    //Echo - Ultrasonic sensor connected to NodeMCU GPIO12 i.e.D6

float garb_cm=0.0;     // Values read from Ultrasonic sensor

void garbage_level()
{
  // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  digitalWrite(trigPin, LOW);
  delayMicroseconds(5);

  //Start sensor reading
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
 
  // Read the signal from the sensor: a HIGH pulse whose
  // duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(echoPin, INPUT);
  long duration = pulseIn(echoPin, HIGH);
 
  // convert the time into a distance
  garb_cm = (duration/2) / 29.1;
  
  Serial.print(garb_cm);
  Serial.print(" cm");
  Serial.println();
  garb_cm = map(garb_cm, 0, 400, 0, 100);
}



void setup()
{
    Serial.begin(115200);
    Serial.println("");
    Serial.println("-------------------------------Garbage Level-------------------------------------");

    pinMode(trigPin, OUTPUT);
    pinMode(echoPin, INPUT);
}

void loop()
{
garbage_level();
delay(5000);
}

Sensors Interfacing and Serial Debugging

Arduino
Reading Ultrasonic sensor's and DS18B20 Temperature Sensor's value and displaying it on serial monitor.
#include <OneWire.h>
#include <DallasTemperature.h>

/********************************************Ultrasonic sensors******************************************************
Esp8266 GPIO pin 12 connected to Echo Pin of HC-SR04
Esp8266 GPIO pin 14 connected to Trigger pin of HC-SR04

Since echo output is 5v 
We have coonected a 2.2K resistor to it then a 4.7K Resistor 
4.7K resistor is grounded
The signal is taken out from the junction of the two resistor
*********************************************************************************************************************/
#define echoPin 12 // Echo Pin
#define trigPin 14 // Trigger Pin

long duration, distance; // Duration used to calculate distance



/********************************************DS18B20 Digital Temperature Sensor***************************************
<OneWire.h> and  <DallasTemperature.h> Library required for DS18B20
DS18B20 Data wire is plugged into GPIOpin 2 on the Esp8266
*********************************************************************************************************************/
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

// Assign the unique addresses of your 1-Wire temp sensors
DeviceAddress insideThermometer = { 0x28, 0xFF, 0x2B, 0x09, 0x16, 0x15, 0x03, 0x39 };
 
float temp_c=0.0;          // Values read from Temperature sensor


void getTemperature(DeviceAddress deviceAddress)
{
    sensors.requestTemperatures();
    temp_c = sensors.getTempC(deviceAddress);
    if (temp_c == -127.00) {
    temp_c=0.0;
    Serial.println("Error getting temperature");
    } 
    else {
    Serial.print("Inside temperature is: ");
    Serial.print(temp_c);
    Serial.print( char(176)); 
    Serial.println("C.");   }
}

void getGarbageLevel(void)
{
/********************************************Ultrasonic sensors******************************************************
  Speed of sound = 340 m/s
  Now,         1 metre = 100 centimetre            and              1 seconds = 1000000 microseconds
  Speed of sound = 340 * 100 cm/(1000000 microseconds) = 0.034 cm per us = (1/29.412) cm per us 
  The Ultrasonic burst travels out & back.So to we have to divide the time the echo pin was high by 2
  Distance = (Time echo pin was high/2) * speed of sound
           = (Time echo pin was high/2) * (1/29.412)
           = (Time echo pin was high/58.82) 
*********************************************************************************************************************/  

digitalWrite(trigPin, LOW);      // Give a short LOW pulse beforehand to ensure a clean HIGH pulse
delayMicroseconds(2);

digitalWrite(trigPin, HIGH);     // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

/**************************************************************
Read the signal from the sensor (Echo pin): a HIGH pulse whose duration is the time (in microseconds) from the sending
of the ping to the reception of its echo off of an object.

pulseIn function reads a pulse (either HIGH or LOW) on a pin. For example, if value is HIGH, pulseIn() waits for the pin 
to go HIGH, starts timing, then waits for the pin to go LOW and stops timing. Returns the length of the pulse in microseconds 
or 0 if no complete pulse was received within the timeout.
Works on pulses from 10 microseconds to 3 minutes in length. Please also note that if the pin is already high when the function
is called, it will wait for the pin to go LOW and then HIGH before it starts counting.
**************************************************************/
duration = pulseIn(echoPin, HIGH);

//Calculate the distance (in cm) based on the speed of sound.
distance = duration/58.82;
Serial.print("Garbage Level: ");
Serial.print(distance);  
Serial.println("cm");
}

void setup()
{
Serial.begin (115200);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
 // Start up the library
sensors.begin();
// set the resolution to 10 bit (good enough?)
sensors.setResolution(insideThermometer, 12);
}
 
void loop()
{
getGarbageLevel();

getTemperature(insideThermometer);

//Delay 50ms before next reading.
delay(2500);
}

Eco Smart Trash Can Code v2.0

Arduino
In this code just Garbage level and temperature inside the trash container is read and uploaded to Artik Cloud by Esp8266.
#include <ESP8266WiFi.h>        //Require to access Wi-Fi funtionality of Esp8266
#include <MQTTClient.h>         //Require to send Data to Artik Cloud via MQTT
#include <ArduinoJson.h>        //Require to send Data to Artik Cloud must be json format

#include <OneWire.h>            //Require for One wire interface as used for DS18B20 
#include <DallasTemperature.h>  //Require for reading temperature from DS18B20

/********************************************Ultrasonic sensors******************************************************
Esp8266 GPIO pin 12 connected to Echo Pin of HC-SR04
Esp8266 GPIO pin 14 connected to Trigger pin of HC-SR04

Since echo output is 5v 
We have coonected a 2.2K resistor to it then a 4.7K Resistor 
4.7K resistor is grounded
The signal is taken out from the junction of the two resistor
*********************************************************************************************************************/
#define echoPin 12 // Echo Pin
#define trigPin 14 // Trigger Pin

long duration, distance; // Duration used to calculate distance


//Working Video: https://youtu.be/tIAWvJ6ZBM8

/********************************************DS18B20 Digital Temperature Sensor***************************************
<OneWire.h> and  <DallasTemperature.h> Library required for DS18B20
DS18B20 Data wire is plugged into GPIOpin 2 on the Esp8266
*********************************************************************************************************************/
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

// Assign the unique addresses of your 1-Wire temp sensors
DeviceAddress insideThermometer = { 0x28, 0xFF, 0x2B, 0x09, 0x16, 0x15, 0x03, 0x39 };
 
float temp_c=0.0;          // Values read from Temperature sensor


/********************************************WiFi Access**************************************************************
Enter the SSID and PASSWORD of your Wi-Fi Router
*********************************************************************************************************************/
const char* _SSID     = "YOUR_SSID";           //Wi-Fi SSID 
const char* _PASSWORD = "YOUR_PASSWORD";     // Wi-Fi Password 


/********************************************Artik cloud Access*******************************************************
MQTT - Artik Cloud Server params
Requires Device ID and Device Token which are created when you make your device in Artik Cloud!!
*********************************************************************************************************************/
char Artik_Cloud_Server[]     = "api.artik.cloud";                                // Server 
int  Artik_Cloud_Port         = 8883;                                             // MQTT Port
char Client_Name[] = "ARTIK-IoT";                                                 // Any Name 
char Device_ID[]   = "822a647ea36b4fa39f1b6c41f0606c52";                          // DEVICE ID
char Device_TOKEN[]   = "8b2e3dd50b594d01a42a12a25513551a";                       // DEVICE TOKEN
char MQTT_Publish[]      = "/v1.1/messages/822a647ea36b4fa39f1b6c41f0606c52";     // (/v1.1/messages/"DEVICE ID")

char buf[200]; // Json Data to Artik Cloud 
char receivebuf[200]; // Json Data from Artik Cloud 


unsigned long lastMillis = 0;                                                     //Data will be sent periodically using millis()

WiFiClientSecure SSL_ESP;                                                         // ESP SSL Connection to Artik cloud 
MQTTClient MQTT_Artik_Client;                                                     // MQTT Protocol


/********************************************DS18B20 Temperature Sensor***********************************************
getTemperature(DeviceAddress deviceAddress)--> Using DS18B20 Digital Temperature Sensor's Address we are reading the 
current temperature in celsius and store in the global variable temp_c
*********************************************************************************************************************/
void getTemperature(DeviceAddress deviceAddress)
{
    sensors.requestTemperatures();
    temp_c = sensors.getTempC(deviceAddress);
    if (temp_c == -127.00) {
    temp_c=0.0;
    Serial.println("  Error getting temperature");
    } 
    else {
    Serial.print("  Trash Container temperature is: ");
    Serial.print(temp_c);
    Serial.print(char(176)); 
    Serial.println(" Celsius.");   }
}

/********************************************HC SR04 Ultrasonic Sensor************************************************
getGarbageLevel(void)--> Getting the garbage level in centimeter using ultrasonic sensor and storing it in global variable distance.
*********************************************************************************************************************/
void getGarbageLevel(void)
{
/********************************************Ultrasonic sensors******************************************************
  Speed of sound = 340 m/s
  Now,         1 metre = 100 centimetre            and              1 seconds = 1000000 microseconds
  Speed of sound = 340 * 100 cm/(1000000 microseconds) = 0.034 cm per us = (1/29.412) cm per us 
  The Ultrasonic burst travels out & back.So to we have to divide the time the echo pin was high by 2
  Distance = (Time echo pin was high/2) * speed of sound
           = (Time echo pin was high/2) * (1/29.412)
           = (Time echo pin was high/58.82) 
*********************************************************************************************************************/  

digitalWrite(trigPin, LOW);      // Give a short LOW pulse beforehand to ensure a clean HIGH pulse
delayMicroseconds(2);

digitalWrite(trigPin, HIGH);     // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

/**************************************************************
Read the signal from the sensor (Echo pin): a HIGH pulse whose duration is the time (in microseconds) from the sending
of the ping to the reception of its echo off of an object.

pulseIn function reads a pulse (either HIGH or LOW) on a pin. For example, if value is HIGH, pulseIn() waits for the pin 
to go HIGH, starts timing, then waits for the pin to go LOW and stops timing. Returns the length of the pulse in microseconds 
or 0 if no complete pulse was received within the timeout.
Works on pulses from 10 microseconds to 3 minutes in length. Please also note that if the pin is already high when the function
is called, it will wait for the pin to go LOW and then HIGH before it starts counting.
**************************************************************/
duration = pulseIn(echoPin, HIGH);

//Calculate the distance (in cm) based on the speed of sound.
distance = duration/58.82;
Serial.print("  Garbage Level: ");
Serial.print(distance);  
Serial.println(" cm");
}

/********************************************MQTT Connection***********************************************************
connect()--> Using this function we first try to connect to the WiFi and if connected then we try connection with MQTT
server using Device ID and Device Token and if connected then we go further else we try again till connection is 
established
*********************************************************************************************************************/
void connect() {
  Serial.println("  Checking wifi...");
  Serial.print("  ");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }

  Serial.println("");
  Serial.println("  Wi-Fi Connected!!");
  while (!MQTT_Artik_Client.connect(Client_Name, Device_ID, Device_TOKEN)) {
    Serial.print("*");
    delay(1000);
  }

  Serial.println("  Client connected to Artik!!");
}

/********************************************Arduino Setup**************************************************************
setup()--> The setup() function is called when a sketch starts. Use it to initialize serial/i2c communication, variables, 
pin modes, start using libraries, etc. The setup function will only run once, after each powerup or reset of the 
Arduino board(or Esp8266). After initializing Serial, pin modes, and sensors we call WiFi.begin to pass WiFi credentials
and then we call and pass MQTT credentials via MQTT_Artik_Client.begin in which MQTT_Artik_Client
***********************************************************************************************************************/
void setup()
{
    Serial.begin (115200);
    Serial.println("");  
    Serial.println("");
    Serial.println("********************************Eco-A Smart Trash Container********************************");
    pinMode(trigPin, OUTPUT);
    pinMode(echoPin, INPUT);
     // Start up the library
    sensors.begin();
    // set the resolution to 10 bit (good enough?)
    sensors.setResolution(insideThermometer, 12);
    
    // Wifi Setting
    WiFi.begin(_SSID, _PASSWORD);
    
    MQTT_Artik_Client.begin(Artik_Cloud_Server, Artik_Cloud_Port, SSL_ESP); // Connect to Artik Server
    
    connect();
}

/********************************************Arduino Loop*********************************************************************************
loop()--> After creating a setup() function, which initializes and sets the initial values, the loop() function does 
precisely what its name suggests, and loops consecutively, allowing your program to change and respond. Use it to 
actively control the Arduino board(or Esp8266).
In our function we first call MQTT client loop and then check whether our MQTT client is connected or not if not then
we call connect function. If connected we publish a message roughly every second for which we have used millis function

millis function--> Returns the number of milliseconds since the Arduino board began running the current program. 
This number will overflow (go back to zero), after approximately 50 days.

Check to see if it's time to publish the sensor data; that is, if the difference between the current time (we get it using millis) 
and last time is bigger than the interval we publish the data. Before publishing the sensor data we read all the sensor data using 
the respective function like for temperature we call getTemperature and for Garbage level we call getGarbageLevel. The difference is
kept at 60*1000 = 60,000 milli-seconds = 60 seconds. for publishing data we use sendToArtikCloud and loadBuffer function explained below
******************************************************************************************************************************************/
void loop()
{
    MQTT_Artik_Client.loop();
    delay(10); 
    
    if(!MQTT_Artik_Client.connected()) {
      connect();
    }
    
    // publish a message roughly every second.
    if(millis() - lastMillis > 60*1000) 
    {
      Serial.println("");
      Serial.println("  Reading Sensor Value");
      getGarbageLevel();
      getTemperature(insideThermometer);
      Serial.println("  Uploading Started!!");
      sendToArtikCloud();
      Serial.println("  Publishing Ended!!");
      lastMillis = millis(); // save the last time you published the data
    } 
}

/********************************************sendToArtikCloud***********************************************************
sendToArtikCloud--> We call loadBuffer to generate the sensor data in json format and then publish it using MQTT
publish function
***********************************************************************************************************************/
void sendToArtikCloud(void) 
{      
      loadBuffer();  // Publishing data list 
    
      MQTT_Artik_Client.publish(MQTT_Publish, buf);// Publishing data to the Artik Cloud 
      delay(3000);
      Serial.println("  Publishing..");      
}

/********************************************loadBuffer*****************************************************************
loadBuffer--> Defined in ArduinoJSON library and required for generating sensor data in json format. As artik cloud
accepts sensor data only in json format.

Step 1: Reserve memory space
Arduino JSON uses a preallocated memory pool to store the object tree; this is done by the StaticJsonBuffer.
In the case of a StaticJsonBuffer, the memory is reserved on the stack. The template parameter (200 in the example) is 
the number of bytes to reserved.

Step 2: Build object tree in memory
Once the JsonBuffer is ready, you can use it to build your in-memory representation of the JSON string.You create an 
object like this:
JsonObject& object = jsonBuffer.createObject();
Don't forget the & after JsonObject, it needs to be a reference to the object.
Then you can add strings, integer, booleans, etc:
object["key1"] = "bazinga!";
object["key2"] = 42;
object["key3"] = true;

Step 3: Generate the JSON string
Whether you have a JsonArray& or a JsonObject&, simply call printTo() with the destination buffer, like so:
char buffer[200];
object.printTo(buffer, sizeof(buffer));
***********************************************************************************************************************/
void loadBuffer(void) {
  StaticJsonBuffer<200> jsonBuffer;
  JsonObject& dataPair = jsonBuffer.createObject();
  dataPair["GarbageLevel"] = distance ;
  dataPair["Temperature"] = temp_c ;
  dataPair.printTo(buf, sizeof(buf));
  Serial.print("  Data Buffer: ");
  Serial.println(buf);
}

/********************************************messageReceived**************************************************************
messageReceived--> required for receiving data from Artik cloud but we do not want this in our project it is kept here as
i found that if you remove this function and compile for ESP8266 you get many errors so i kept it and voila no errors and
compilation sucessfull!!
***********************************************************************************************************************/
void messageReceived(String topic, String payload, char * bytes, unsigned int length) 
{ 
  
} 

Credits

Amol Disale

Amol Disale

9 projects • 100 followers
I am passionate about the idea of open-source hardware and software. I am ready to help in prototyping IoT, Smart Home, and other products.

Comments