H2Oh

The Smart Water Dispenser

- Nipun Kanade

Just Another ThoughtWorker

WhatThe Good ??

is H2Oh

This

whaaat ???

Ooops.. that was from a previous project..

H2Oh

Is an internet connected water dispenser, which can identify you from your id card, measure the amount of water you draw from it and posts it to a server

Yo !! I'm all ears...

So how do we build it ?

Let's start with the Hardware

Blink the LED


void setup() {
  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);              // wait for a second
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);              // wait for a second
}

Become Sherlock - Find the user

/*
 * HID RFID Reader Wiegand Interface for Arduino Uno
 * Written by Daniel Smith, 2012.01.30
 * www.pagemac.com
 *
 * This program will decode the wiegand data from a HID RFID Reader (or, theoretically,
 * any other device that outputs weigand data).
 * The Wiegand interface has two data lines, DATA0 and DATA1.  These lines are normall held
 * high at 5V.  When a 0 is sent, DATA0 drops to 0V for a few us.  When a 1 is sent, DATA1 drops
 * to 0V for a few us.  There is usually a few ms between the pulses.
 *
 * Your reader should have at least 4 connections (some readers have more).  Connect the Red wire 
 * to 5V.  Connect the black to ground.  Connect the green wire (DATA0) to Digital Pin 2 (INT0).  
 * Connect the white wire (DATA1) to Digital Pin 3 (INT1).  That's it!
 *
 * Operation is simple - each of the data lines are connected to hardware interrupt lines.  When
 * one drops low, an interrupt routine is called and some bits are flipped.  After some time of
 * of not receiving any bits, the Arduino will decode the data.  I've only added the 26 bit and
 * 35 bit formats, but you can easily add more.
 
*/
 
 
#define MAX_BITS 100                 // max number of bits 
#define WEIGAND_WAIT_TIME  3000      // time to wait for another weigand pulse.  
 
unsigned char databits[MAX_BITS];    // stores all of the data bits
unsigned char bitCount;              // number of bits currently captured
unsigned char flagDone;              // goes low when data is currently being captured
unsigned int weigand_counter;        // countdown until we assume there are no more bits
 
unsigned long facilityCode=0;        // decoded facility code
unsigned long cardCode=0;            // decoded card code
 
// interrupt that happens when INTO goes low (0 bit)
void ISR_INT0()
{
  //Serial.print("0");   // uncomment this line to display raw binary
  bitCount++;
  flagDone = 0;
  weigand_counter = WEIGAND_WAIT_TIME;  
 
}
 
// interrupt that happens when INT1 goes low (1 bit)
void ISR_INT1()
{
  //Serial.print("1");   // uncomment this line to display raw binary
  databits[bitCount] = 1;
  bitCount++;
  flagDone = 0;
  weigand_counter = WEIGAND_WAIT_TIME;  
}
 
void setup()
{
  pinMode(13, OUTPUT);  // LED
  pinMode(2, INPUT);     // DATA0 (INT0)
  pinMode(3, INPUT);     // DATA1 (INT1)
 
  Serial.begin(9600);
  Serial.println("RFID Readers");
 
  // binds the ISR functions to the falling edge of INTO and INT1
  attachInterrupt(0, ISR_INT0, FALLING);  
  attachInterrupt(1, ISR_INT1, FALLING);
 
 
  weigand_counter = WEIGAND_WAIT_TIME;
}
 
void loop()
{
  // This waits to make sure that there have been no more data pulses before processing data
  if (!flagDone) {
    if (--weigand_counter == 0)
      flagDone = 1;	
  }
 
  // if we have bits and we the weigand counter went out
  if (bitCount > 0 && flagDone) {
    unsigned char i;
 
    Serial.print("Read ");
    Serial.print(bitCount);
    Serial.print(" bits. ");
 
    // we will decode the bits differently depending on how many bits we have
    // see www.pagemac.com/azure/data_formats.php for mor info
    if (bitCount == 35)
    {
      // 35 bit HID Corporate 1000 format
      // facility code = bits 2 to 14
      for (i=2; i<14; i++)
      {
         facilityCode <<=1;
         facilityCode |= databits[i];
      }
 
      // card code = bits 15 to 34
      for (i=14; i<34; i++)
      {
         cardCode <<=1;
         cardCode |= databits[i];
      }
 
      printBits();
    }
    else if (bitCount == 26)
    {
      // standard 26 bit format
      // facility code = bits 2 to 9
      for (i=1; i<9; i++)
      {
         facilityCode <<=1;
         facilityCode |= databits[i];
      }
 
      // card code = bits 10 to 23
      for (i=9; i<25; i++)
      {
         cardCode <<=1;
         cardCode |= databits[i];
      }
 
      printBits();  
    }
    else {
      // you can add other formats if you want!
     Serial.println("Unable to decode."); 
    }
 
     // cleanup and get ready for the next card
     bitCount = 0;
     facilityCode = 0;
     cardCode = 0;
     for (i=0; i<MAX_BITS; i++) 
     {
       databits[i] = 0;
     }
  }
}
 
void printBits()
{
      // I really hope you can figure out what this function does
      Serial.print("FC = ");
      Serial.print(facilityCode);
      Serial.print(", CC = ");
      Serial.println(cardCode); 
}

The Capacitive Switch

Let's See how can we monitor amount of water dispensed 

Let's Connect it to World

//example request : http://10.132.127.212:3000/order?type=juice&deviceID=123&userID=18427

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>

#include <SoftwareSerial.h>

SoftwareSerial arduino(D5, D7, false, 256);

#define buzzer D6
#define red D4
#define green D3
#define blue D2

ESP8266WiFiMulti WiFiMulti;
HTTPClient http;
        
String url;
String payload;

void setup() {

    pinMode(red, OUTPUT);
    pinMode(blue, OUTPUT);
    pinMode(green, OUTPUT);
    pinMode(buzzer, OUTPUT);

    digitalWrite(red, LOW);
    digitalWrite(green, HIGH);
    digitalWrite(blue, HIGH);
    digitalWrite(buzzer, LOW);

    Serial.begin(9600);
    arduino.begin(9600);
    Serial.println();
    Serial.println();
    Serial.println();

    for(uint8_t t = 4; t > 0; t--) {
        Serial.printf("[SETUP] WAIT %d...\n", t);
        Serial.flush();
        delay(1000);
    }

    WiFiMulti.addAP("SSID", "PASSWORD");

}

void buzz(int delayTime){
    digitalWrite(buzzer, HIGH);
    delay(delayTime);
    digitalWrite(buzzer, LOW);  
}

void buzzInt(int delayTime, int repeat, int stopDelay){
    while(repeat>0){
    buzz(delayTime);
    delay(stopDelay);
    repeat--;
    }
}    
    

void loop() {
  
    digitalWrite(red, LOW);
    digitalWrite(blue, HIGH);
    digitalWrite(green,HIGH);
         
    if((WiFiMulti.run() == WL_CONNECTED)) {

     digitalWrite(red, HIGH);
     digitalWrite(red, HIGH);
     digitalWrite(blue, LOW);
     delay(500);

     if(Serial.available() > 0) {        
        
        url = Serial.readStringUntil('\n');
        String toBeSentURl = url.substring(0, url.length()-1);
        Serial.print("Got : ");
        Serial.println(toBeSentURl);
        
        Serial.print("[HTTP] begin...\n");
        http.begin(toBeSentURl); //HTTP
        Serial.print("[HTTP] GET...\n");
        int httpCode = http.GET();
        
        
        Serial.printf("[HTTP] GET... code: %d\n", httpCode);

        if(httpCode > 0) {
           
            
            if(httpCode == HTTP_CODE_OK) {
     
                String payload = http.getString();
                Serial.println(payload);

                
                digitalWrite(blue, LOW);
                digitalWrite(green, LOW);
                digitalWrite(red, LOW);
                delay(300);
                buzzInt(100,3,100);
                

             }
             else {

                Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
                digitalWrite(blue, LOW);
                digitalWrite(green, HIGH);
                digitalWrite(red, LOW);
                buzz(1500);
             }

           }
          
          http.end();
        }

        digitalWrite(red, HIGH);
        digitalWrite(blue, LOW);
        digitalWrite(green,HIGH);
        Serial.flush();
      }
}


Backend / Frontend

  1. Any tech of your choice
  2. A REST Server is needed
  3. A DB , preferably nosql
  4. Admin Console
  5. User Dashboard

Integration Time

Text

Text

Connections

#include <CapacitiveSensor.h>
String url="http://10.134.124.214:8083/api/waterdispenser/consumption/new/internalNumber/";

int buttonState = 0;
long startMillis = 0;
long stopMillis = 0;
long timeCount = 0;
long volume = 0;

unsigned int cardLed = 10;
unsigned int dispenserLed = 9;
unsigned int sensor = 8;
unsigned int capacitorPin = 2;
unsigned int resistorPin = 4;
#define MAX_BITS 100                 // max number of bits 
#define WEIGAND_WAIT_TIME  3000      // time to wait for another weigand pulse.  
 
unsigned char databits[MAX_BITS];    // stores all of the data bits
unsigned char bitCount;              // number of bits currently captured
unsigned char flagDone;              // goes low when data is currently being captured
unsigned int weigand_counter;        // countdown until we assume there are no more bits
 
unsigned long facilityCode=0;        // decoded facility code
unsigned long cardCode=0;            // decoded card code

CapacitiveSensor   cs_4_5 = CapacitiveSensor(4,5); 

void ISR_INT0()
{
  bitCount++;
  flagDone = 0;
  weigand_counter = WEIGAND_WAIT_TIME;  
 
}
 

void ISR_INT1()
{
  databits[bitCount] = 1;
  bitCount++;
  flagDone = 0;
  weigand_counter = WEIGAND_WAIT_TIME;  
}
 
void setup()
{
  pinMode(2, INPUT);     // DATA0 (INT0)
  pinMode(3, INPUT);     // DATA1 (INT1)
  pinMode(sensor, INPUT);
  
  pinMode(cardLed, OUTPUT);
  pinMode(dispenserLed, OUTPUT);
  cs_4_5.set_CS_AutocaL_Millis(0xFFFFFFFF);
  Serial.begin(9600);
  digitalWrite(cardLed, LOW);
  digitalWrite(dispenserLed, LOW);
  
  digitalWrite(4, HIGH);
  attachInterrupt(0, ISR_INT0, FALLING);  
  attachInterrupt(1, ISR_INT1, FALLING);
 
  weigand_counter = WEIGAND_WAIT_TIME;
}
 
void loop()
{
  // This waits to make sure that there have been no more data pulses before processing data
  if (!flagDone) {
    if (--weigand_counter == 0)
      flagDone = 1;  
  }
 
  // if we have bits and we the weigand counter went out
  if (bitCount > 0 && flagDone) {
    unsigned char i; 
    if (bitCount == 35)
    {
      for (i=2; i<14; i++)
      {
         facilityCode <<=1;
         facilityCode |= databits[i];
      }
 
      for (i=14; i<34; i++)
      {
         cardCode <<=1;
         cardCode |= databits[i];
      }
 
      printBits();
    }
    else if (bitCount == 26)
    {
      for (i=1; i<9; i++)
      {
         facilityCode <<=1;
         facilityCode |= databits[i];
      }
      for (i=9; i<25; i++)
      {
         cardCode <<=1;
         cardCode |= databits[i];
      }
 
      printBits();  
    }
    
     // cleanup and get ready for the next card
     bitCount = 0;
     facilityCode = 0;
     cardCode = 0;
     for (i=0; i<MAX_BITS; i++) 
     {
       databits[i] = 0;
     }
  }
}
 
void printBits()
{
      digitalWrite(cardLed, HIGH);
      int getVolume = getvol();
      if(getVolume > 20){
        url.concat(cardCode);
        url.concat("/consumption/");
        String vol = String(getVolume);
        url.concat(String(vol));
        Serial.println(url);
        url="http://10.134.124.214:8083/api/waterdispenser/consumption/new/internalNumber/";      
      
      }
      digitalWrite(cardLed, LOW);
}

int getvol(){
  startMillis = 0;
  stopMillis = 0;
  timeCount = 0;
  buttonState = digitalRead(sensor);
  digitalWrite(dispenserLed, LOW);
  long capSense =  cs_4_5.capacitiveSensor(30);
  Serial.println("capsense" + capSense);
  while(capSense < 100 ){
      capSense =  cs_4_5.capacitiveSensor(30);
      if(capSense > 100){
        delay(500);
      capSense =  cs_4_5.capacitiveSensor(30);               
     }
  }
  
  startMillis = millis();
  digitalWrite(dispenserLed, HIGH);
  
  while(capSense > 100){
      capSense =  cs_4_5.capacitiveSensor(30);
  }
  stopMillis = millis(); 
  digitalWrite(dispenserLed, LOW);
  
  timeCount = (stopMillis - startMillis) / 1000;
  volume = map(timeCount, 0, 99, 0, 3000);
  digitalWrite(sensor, HIGH);
  
  return volume; 
}

Final Code

Video

Thats IT !!

Questions ??

Thanks

 

nipunk@thoughtworks.com

twitter : @kanadenipun

 

H2Oh, The smart water dispenser

By Nipun Kanade

H2Oh, The smart water dispenser

  • 82
Loading comments...

More from Nipun Kanade