Taha SiddiqiAaron SmithBecca
Published © GPL3+

Smart Laundry Detergent Dispenser

Dispense detergent using smart home device such as Google Home and Amazon Alexa.

IntermediateShowcase (no instructions)3 hours15
Smart Laundry Detergent Dispenser

Things used in this project

Hardware components

Argon
Particle Argon
×3
Solderless Breadboard Half Size
Solderless Breadboard Half Size
×3
Mini Pushbutton Switches
×3
SparkFun Load Cell Amplifier - HX711
SparkFun Load Cell Amplifier - HX711
×1
Load Cell Combinator
×1
Magnetic Door Switch
×1
Bathroom Scale from Walmart (or a set of four 3 wire load cells)
×1
IRLB8721 N Channel Mofest
×1
12V 6.7A DC power supply (I used one from a phillips respironics machine)
×1
12V Push/Pull Solenoid
×1
Assorted Jumper wires
×1

Software apps and online services

Particle Build Web IDE
Particle Build Web IDE
Maker service
IFTTT Maker service

Hand tools and fabrication machines

Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires

Story

Read more

Custom parts and enclosures

Bracket

Schematics

Door Sensor Schematic

Solenoid Control Schematic

Level Sensor Schematic

Code

Door Sensor

C/C++
int switchstate = 0;
int lastswitchstate = 0;

int switchpin = D1;
int groundpin = D0;
int ledpin = D7;

void setup() {
pinMode(switchpin, INPUT_PULLUP);
pinMode(ledpin, OUTPUT);
pinMode(groundpin, OUTPUT);
digitalWrite(groundpin, LOW);
}

void loop() {
lastswitchstate = switchstate;  //copy the previous switch state to the last switch state
switchstate = digitalRead(D1);  //read a new switch state.

if (switchstate == 0 && (lastswitchstate ==1)){ 
    Particle.publish("door-closed", PRIVATE);  //send the event to the particle cloud

    digitalWrite(ledpin, HIGH);
    delay(500);
    digitalWrite(ledpin, LOW);
    }


else if (switchstate == 1 && (lastswitchstate == 0)){ //if both are true then...  This is a bit more advanced than just detecting a input state. It detects an edge of a signal to prevent overloading the cloud.
    //"==" compares the two values.  If equal it takes a value of "true" or 1.
    Particle.publish("door-open", PRIVATE);  //send the event to the particle cloud

    digitalWrite(ledpin, HIGH);
    delay(500);
    digitalWrite(ledpin, LOW);
    }
}

Scale Calibration

C/C++
No preview (download only).

SolenoidControl

C/C++
const pin_t MY_LED = D7;

int smallSwitchState = 0;
int mediumSwitchState = 0;
int largeSwitchState = 0;
int LASTsmallSwitchState = 0;
int LASTmediumSwitchState = 0;
int LASTlargeSwitchState = 0;
bool doorOpen = false;
int groundpin = D0;
int smallSwitch = D1;
int mediumSwitch = D2;
int largeSwitch = D3;
int solenoid = D4;

SYSTEM_THREAD(ENABLED);

int ledToggleSmall(String command) {
    if (doorOpen == true) {
        digitalWrite(solenoid, HIGH);
        digitalWrite(MY_LED,HIGH);
        
        delay(3000);
        
        digitalWrite(solenoid, LOW);
        digitalWrite(MY_LED,LOW);
        
        delay(3000);
        
        Particle.publish("get-weight", PRIVATE);
    }
 
 return 0;   
}

int ledToggleMedium(String command) {
    if (doorOpen == true){
        digitalWrite(solenoid, HIGH);
        digitalWrite(MY_LED,HIGH);
        
        delay(5000);
        
        digitalWrite(solenoid, LOW);
        digitalWrite(MY_LED,LOW);
        
        delay(3000);
        
        Particle.publish("get-weight", PRIVATE);
    }
 
 return 0;   
}

int ledToggleLarge(String command) {
    if (doorOpen == true){
        digitalWrite(solenoid, HIGH);
        digitalWrite(MY_LED,HIGH);
        
        delay(7000);
        
        digitalWrite(solenoid, LOW);
        digitalWrite(MY_LED,LOW);
        
        delay(3000);
        
        Particle.publish("get-weight", PRIVATE);
    }
 
 return 0;   
}

int openFunc(const char *topic, const char *data){  //this moves the servo to turn off the other switch

    doorOpen = true;
    digitalWrite(MY_LED,HIGH); //blink the led for visual feedback 
    delay(500); //give the servo a chance to move  Pause for 500ms
    digitalWrite(MY_LED,LOW); //turn the led off
    
 return 0;
}

int closedFunc(const char *topic, const char *data){  //this moves the servo to turn off the other switch

    doorOpen = false;
    digitalWrite(MY_LED,HIGH); //blink the led for visual feedback 
    delay(200); //give the servo a chance to move  Pause for 500ms
    digitalWrite(MY_LED,LOW); //turn the led off
    delay(200);
    digitalWrite(MY_LED,HIGH); //blink the led for visual feedback 
    delay(200); //give the servo a chance to move  Pause for 500ms
    digitalWrite(MY_LED,LOW); //turn the led off
    delay(200);
    digitalWrite(MY_LED,HIGH); //blink the led for visual feedback 
    delay(200); //give the servo a chance to move  Pause for 500ms
    digitalWrite(MY_LED,LOW); //turn the led off
    delay(200);
    digitalWrite(MY_LED,HIGH); //blink the led for visual feedback 
    delay(200); //give the servo a chance to move  Pause for 500ms
    digitalWrite(MY_LED,LOW); //turn the led off
    
    
 return 0;
}

void setup() {

pinMode(smallSwitch, INPUT_PULLUP);

pinMode(mediumSwitch, INPUT_PULLUP);

pinMode(largeSwitch, INPUT_PULLUP);

pinMode(groundpin, OUTPUT);

pinMode(MY_LED, OUTPUT);

pinMode(solenoid, OUTPUT);

Particle.function("ledSmall", ledToggleSmall);

Particle.function("ledMedium", ledToggleMedium);

Particle.function("ledLarge", ledToggleLarge);

Particle.subscribe("door-closed", closedFunc, MY_DEVICES);

Particle.subscribe("door-open", openFunc, MY_DEVICES);

}

void loop() {

LASTsmallSwitchState = smallSwitchState;
LASTmediumSwitchState = mediumSwitchState;
LASTlargeSwitchState = largeSwitchState;

smallSwitchState = digitalRead(D1);
mediumSwitchState = digitalRead(D2);
largeSwitchState = digitalRead(D3);


if (doorOpen == true) {
    if (smallSwitchState == 0 && LASTsmallSwitchState == 1){
        ledToggleSmall("ledSmall");
        delay(2000);
    }
    
    else if (mediumSwitchState == 0 && LASTmediumSwitchState == 1){
        ledToggleMedium("ledMedium");
        delay(2000);
    }
    
    else if (largeSwitchState == 0 && LASTlargeSwitchState == 1){
        ledToggleLarge("ledLarge");
        delay(2000);
    }
}
}

Level Sensor

C/C++
// This #include statement was automatically added by the Particle IDE.
#include <HX711ADC.h>

/*
 Example using the SparkFun HX711 breakout board with a scale
 By: Nathan Seidle
 SparkFun Electronics
 Date: November 19th, 2014
 License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

 This example demonstrates basic scale output. See the calibration sketch to get the calibration_factor for your
 specific load cell setup.

 This example code uses bogde's excellent library: https://github.com/bogde/HX711
 bogde's library is released under a GNU GENERAL PUBLIC LICENSE

 The HX711 does one thing well: read load cells. The breakout board is compatible with any wheat-stone bridge
 based load cell which should allow a user to measure everything from a few grams to tens of tons.
 Arduino pin 2 -> HX711 CLK
 3 -> DAT
 5V -> VCC
 GND -> GND

 The HX711 board can be powered from 2.7V to 5V so the Arduino 5V power should be fine.

*/

#include "HX711ADC.h"

#define calibration_factor 10000 //This value is obtained using the SparkFun_HX711_Calibration sketch

#define DOUT  3
#define CLK  2

const pin_t MY_LED = D7;

float weight1;
float weight2;
float weight3;
float weightAvg;
bool shouldGetWeight = false;
double percent;

int weightFunc(const char *topic, const char *data) {
    shouldGetWeight = true;
    
    digitalWrite(MY_LED, HIGH);
    delay(2000);
    digitalWrite(MY_LED, LOW);
    
 return 0;
}
    
    

HX711ADC scale;

void setup() {
  
  pinMode(MY_LED, OUTPUT);  
  
  Serial.begin(9600);
  Serial.println("HX711 scale demo");
  scale.begin(DOUT, CLK);
  scale.set_scale(calibration_factor); //This value is obtained by using the SparkFun_HX711_Calibration sketch
  scale.tare();
  Particle.subscribe("get-weight", weightFunc, MY_DEVICES);
}

void loop() {
 if (shouldGetWeight == true) {
      weight1  = scale.get_units();
      delay(1000);
      weight2  = scale.get_units();
      delay(1000);
      weight3  = scale.get_units();
      weightAvg = (weight1 + weight2 + weight3) / 3;
      percent = (weightAvg / 9) * 100;
      Particle.publish("weight-avg", String(weightAvg));
      Particle.publish("percent-remaining", String(percent));
      delay(5000);
      shouldGetWeight = false;
 }
}

Credits

Taha Siddiqi

Taha Siddiqi

1 project • 3 followers
Aaron Smith

Aaron Smith

1 project • 2 followers
Becca

Becca

1 project • 0 followers

Comments

Add projectSign up / Login