Shower Monitor
-
I have a bunch of teenagers at home... showers can be (are in fact) endless.
This can be analysed from different points of view : waste of money, waste of precious resources, waste of energy to heat that water, ...
One could simply "lock" the amount of water allowed for one shower, by using a flow meter and an electric valve.
Let's try a more civilised approch first: a visual way of knowing instantly the amount of water used.
We shall use :
- flow meter
- arduino
- 1 unit NeoPixel
- power bank
FlowMeter is connected to INT0. Once calibrated it gives "X pusles per minutes" which is the base for the whole program.
LED will be glowing from blue to red. Quantity of water used can be modifed by user.
Water flow can be paused and resumed during the wash.
If a certain amount of time (user modified) is elapsed, the arduino goes to deep sleep and timers/counters are reset.
This project has not been "MySensorised" yet but it might be.I am also willing to integrate the whole lot into the shower head and replace the flow-meter with a water-powered generator (to charge a supercap) and some hall effect sensor (to get pulses from the generator's magnets). An ATTiny85 would do the job!
Here is the code, comments welcome to make it more efficient :
#include <Adafruit_NeoPixel.h> #include <avr/interrupt.h> //libraires to manage sleep mode #include <avr/sleep.h> //libraires to manage sleep mode #define FLOW_PIN 2 //waterflow sensor pin #define LED_PIN A0 //neopixel data pin #define LED_COUNT 1 /*********************** * user defined values * ***********************/ uint32_t maxLitres = 50; // max water quantity. led goes RED ! const float pulsesPerLiter = 570.0; // pulses per litre (adjust after calibration) unsigned long delayBeforeReset = 120000; // delay between last pulse and going to sleep uint32_t startHue = 43690; // hue of blue ( 65536*2/3 ) uint32_t endHue = 0; // hue of red ( 0 ) /*********************** /* end */ ***********************/ uint32_t hueNow; float hueIncrementPerPulse; // = ( startHue - endHue ) / ( pulsesPerLiter * maxLitres float litres = 0; // total water consumption given by "pulses" and "pulse per liter" volatile unsigned long totalPulses = 0; // volatile unsigned long prevTotalPulses = 0; // last total of pulses before next pulse unsigned long timeOfLastPulse = 0; // when the last pulse occured Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800); //data sequence GRBW void setup() { Serial.begin(115200); strip.begin(); delay(200); strip.clear(); strip.show(); // Initialize pixel to 'off' pinMode(FLOW_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(FLOW_PIN), flowISR, RISING); hueIncrementPerPulse = ( startHue - endHue ) / ( pulsesPerLiter * maxLitres ); Serial.print("hueIncrementPerPulse:"); Serial.println(hueIncrementPerPulse); // 3 decimals } void loop() { /**************************** water volume management ****************************/ static unsigned long lastPrintMs = 0; unsigned long now = millis(); if (now - lastPrintMs >= 1000) { noInterrupts(); unsigned long pulses = totalPulses; interrupts(); litres = pulses / pulsesPerLiter; } showHue(); /******************** sleep management ********************/ if ( (millis() - timeOfLastPulse >= delayBeforeReset) && (totalPulses == prevTotalPulses)) { delay(200); enterSleep(); } prevTotalPulses = totalPulses; } void flowISR() { totalPulses++; timeOfLastPulse = millis(); } void showHue() { if( litres >= maxLitres ) { hueNow = 0; } else { hueNow = startHue - (totalPulses * hueIncrementPerPulse ) ; } uint32_t rgbcolor = strip.ColorHSV(hueNow); strip.setPixelColor(0, rgbcolor); strip.show(); } void enterSleep(void) { sleep_enable(); attachInterrupt(digitalPinToInterrupt(FLOW_PIN), pin2Interrupt, LOW); // Setup pin2 as an interrupt and attach handler set_sleep_mode(SLEEP_MODE_PWR_DOWN); strip.clear(); strip.show(); // Initialize pixel to 'off' totalPulses = 0; litres = 0; timeOfLastPulse = millis(); delay(1000); sleep_cpu(); /* Program will start from here on after wake up */ sleep_disable(); } void pin2Interrupt(void) { Serial.println("Exiting sleep"); // This will bring us back from sleep detachInterrupt(0); // We detach the interrupt to stop it from continuously firing while the interrupt pin is low. attachInterrupt(digitalPinToInterrupt(FLOW_PIN), flowISR, RISING); }I am using "Hue" instead of "RGB" as it simplifies a lot the process of following a ranibow !
-
First, my sympathies and empathies. Remember, this, too, shall pass. Perhaps you will become a grandparent and get your revenge by spoiling the grandkids rotten.
Cool project! I use the same flow meter and have found it very reliable. I, too, think the idea of realtime feedback is much better than the shut-off valve which would also double the cost of the project.
And, if you do become a grandparent, you can offer to remove and install it in your offspring's abode. ;)
-OSD
-
First, my sympathies and empathies. Remember, this, too, shall pass. Perhaps you will become a grandparent and get your revenge by spoiling the grandkids rotten.
Cool project! I use the same flow meter and have found it very reliable. I, too, think the idea of realtime feedback is much better than the shut-off valve which would also double the cost of the project.
And, if you do become a grandparent, you can offer to remove and install it in your offspring's abode. ;)
-OSD
@OldSurferDude :D that's the smell of experience !
Even though things come eventually to an end (with great sadness i'm afraid) this had to be addressed.
What kind of flow do you measure then ?