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
- Any tech of your choice
- A REST Server is needed
- A DB , preferably nosql
- Admin Console
- 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
- 418