Arduino Sink Starter Averager
Who uses cold water?! Ugh. Adapting to an existing faucet, a recessed motion triggered sink starter to average temperature. Includes a photoresistor as a fail safe and Neopixels for a Pavlovian conditioning.


Arduino Nano
Elegoo Obstacle Detector
MG995S Servos (x2)
9G Servos (x2)
1000 uf Capacitor
Photoresistor
330 ohm Resistor
1K ohm Resistor
5V Power Supply



Updated: 288-021
Removed the light sensor as the motion sensor was adjusted to a minimum where it proved unlikely to randomly trigger. Replaced the light sensor with a momentary button as a power outage requisite reset to prevent errant servo reset (turning the sink on) upon powering without user awareness. If a power outage occurred, the entire unit is inactive and will flash red until the user presses the button.

// sink starter
// vije miller
// updated with button restore

#include "FastLED.h"
#define NUM_LEDS 30
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
#define PIN 16
int data = 255;
int r = 0;
int g = 0;
int b = 255;
int j = 0;
int k = 0;

#include <VarSpeedServo.h>
VarSpeedServo left;
VarSpeedServo l_lift;
VarSpeedServo right;
VarSpeedServo r_lift;
const int left_pin = 3;
const int l_lift_pin = 5;
const int right_pin = 7;
const int r_lift_pin = 9;

const int rldown = 100;
const int lldown = 80;
const int rlup = 6;
const int llup = 180;
const int lup = 10;
const int rup = 170;
const int ldown_second = 92;
const int rdown_second = 100;

const int button = 18;
const int motion = 11;
int ismoved;

void setup() {

pinMode(motion, INPUT);
pinMode(button, INPUT);

FastLED.addLeds<LED_TYPE, PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );

// wait for user activation
// power outage safety
while (digitalRead(button) == LOW) {
neoshow(255, 0, 0, 150);
delay(500);
neoshow(0, 0, 0, 150);
delay(500);
}

l_lift.attach(l_lift_pin);
r_lift.attach(r_lift_pin);
delay(1000); // default error fix
right.attach(right_pin);
left.attach(left_pin);
delay(500);

l_lift.write(lldown, 255, false);
r_lift.write(rldown, 255, true);
delay(1000);
left.write(lup, 100, false);
right.write(rup, 100, true);
delay(1000);
l_lift.write(llup, 180, false);
r_lift.write(rlup, 180, true);
delay(500);

l_lift.detach();
r_lift.detach();
left.detach();
right.detach();

colorWipe(0x00, 0x00, 0xff, 50);
neoshow(0, 0, 255, 220);
}

void loop() {
// if motion
ismoved = digitalRead(motion);
if (ismoved == LOW) {
doit();
} else {
delay(10);
}
}

void doit() {
// reconnect pins
l_lift.attach(l_lift_pin);
r_lift.attach(r_lift_pin);
right.attach(right_pin);
left.attach(left_pin);
// give it a chance
delay(100);
// lift down first
l_lift.write(lldown, 255, false);
r_lift.write(rldown, 255, true);
delay(500);
// push
left.write(ldown_second, 200, false);
right.write(rdown_second, 200, true);
delay(500);
// return
left.write(lup, 200, false);
right.write(rup, 200, true);
delay(500);
// lift
l_lift.write(llup, 100, false);
r_lift.write(rlup, 100, true);
delay(500);
// disconnect pins
l_lift.detach();
r_lift.detach();
left.detach();
right.detach();
// pavlov
lightshow();
}

void lightshow() {
j = random(1, 3);
if (j == 1) {
for (k = 0; k < 10; k++) {
TwinkleRandom(20, 100, false);
}
} else if (j == 2) {
for (k = 0; k < 2; k++) {
rainbowCycle(20);
}
} else if (j == 3) {
for (k = 0; k < 3; k++) {
colorWipe(random(255), random(255), random(255), 50);
colorWipe(0, 0, 0, 50);
}
}
neoshow(random(255), random(255), random(255), 220);
}

void neoshow(int r, int g, int b, int brightness) {
Serial.println(r);
Serial.println(g);
Serial.println(b);
FastLED.setBrightness(brightness);
for (int i = 0; i < NUM_LEDS; i++ )
{
leds[i] = CRGB(r, g, b);
}
FastLED.show();
}

void showStrip() {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.show();
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
FastLED.show();
#endif
}

void setPixel(int Pixel, byte red, byte green, byte blue) {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.setPixelColor(Pixel, strip.Color(red, green, blue));
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
leds[Pixel].r = red;
leds[Pixel].g = green;
leds[Pixel].b = blue;
#endif
}

void setAll(byte red, byte green, byte blue) {
for (int i = 0; i < NUM_LEDS; i++ ) {
setPixel(i, red, green, blue);
}
showStrip();
}

void rainbowCycle(int SpeedDelay) {
byte *c;
uint16_t i, j;
for (j = 0; j < 256 * 5; j++) { // 5 cycles of all colors on wheel
for (i = 0; i < NUM_LEDS; i++) {
c = Wheel(((i * 256 / NUM_LEDS) + j) & 255);
setPixel(i, *c, *(c + 1), *(c + 2));
}
showStrip();
delay(SpeedDelay);
}
}

byte * Wheel(byte WheelPos) {
static byte c[3];
if (WheelPos < 85) {
c[0] = WheelPos * 3;
c[1] = 255 - WheelPos * 3;
c[2] = 0;
} else if (WheelPos < 170) {
WheelPos -= 85;
c[0] = 255 - WheelPos * 3;
c[1] = 0;
c[2] = WheelPos * 3;
} else {
WheelPos -= 170;
c[0] = 0;
c[1] = WheelPos * 3;
c[2] = 255 - WheelPos * 3;
}
return c;
}

void TwinkleRandom(int Count, int SpeedDelay, boolean OnlyOne) {
setAll(0, 0, 0);
for (int i = 0; i < Count; i++) {
setPixel(random(NUM_LEDS), random(0, 255), random(0, 255), random(0, 255));
showStrip();
delay(SpeedDelay);
if (OnlyOne) {
setAll(0, 0, 0);
}
}
delay(SpeedDelay);
}

void colorWipe(byte red, byte green, byte blue, int SpeedDelay) {
for (uint16_t i = 0; i < NUM_LEDS; i++) {
setPixel(i, red, green, blue);
showStrip();
delay(SpeedDelay);
}
}


@pkvi
"...may not meet professional standards."
12,127 miters
1 miter today
202 tenons
Subscribe