From 0423bd15122eaebb2295a5147e05c483eff28034 Mon Sep 17 00:00:00 2001 From: rob tillaart Date: Tue, 6 Dec 2022 16:57:55 +0100 Subject: [PATCH] 0.1.2 RAIN --- libraries/rain/CHANGELOG.md | 13 ++- libraries/rain/README.md | 96 ++++++++++++++----- .../rain/examples/rain_delta/rain_delta.ino | 2 + .../rain/examples/rain_demo/rain_demo.ino | 4 + .../rain_demo_powerpin/rain_demo_powerpin.ino | 38 ++++++++ .../rain_digital_out/rain_digital_out.ino | 48 ++++++++++ .../rain_interrupt/rain_interrupt.ino | 57 +++++++++++ .../rain_setLevel_guard_low.ino | 18 ++-- libraries/rain/keywords.txt | 8 ++ libraries/rain/library.json | 6 +- libraries/rain/library.properties | 8 +- libraries/rain/rain.cpp | 58 +++++++++-- libraries/rain/rain.h | 32 +++++-- 13 files changed, 332 insertions(+), 56 deletions(-) create mode 100644 libraries/rain/examples/rain_demo_powerpin/rain_demo_powerpin.ino create mode 100644 libraries/rain/examples/rain_digital_out/rain_digital_out.ino create mode 100644 libraries/rain/examples/rain_interrupt/rain_interrupt.ino diff --git a/libraries/rain/CHANGELOG.md b/libraries/rain/CHANGELOG.md index 08271cdf..abd031b5 100644 --- a/libraries/rain/CHANGELOG.md +++ b/libraries/rain/CHANGELOG.md @@ -6,6 +6,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.1.2] - 2022-12-06 +- add powerPin to constructor. Optional. +- add powerPin example +- add interrupt example (using DO = digital Out) +- add digital out polling example +- update readme.md (lower voltage == wetter) +- fix version number +- fix percentage() => 0% == DRY and 100% == WET +- add get- and setDryReference() for better percentage() behaviour. +- update keywords.txt + + ## [0.1.1] - 2022-12-03 - change levels to milliVolts (uint16_t). - rewrite setLevel(milliVolts) and getLevel(). @@ -14,7 +26,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - update keywords.txt - add delta() => delta with previous read(). - ## [0.1.0] - 2022-12-03 - initial version diff --git a/libraries/rain/README.md b/libraries/rain/README.md index 5275385f..dffdf6f1 100644 --- a/libraries/rain/README.md +++ b/libraries/rain/README.md @@ -13,45 +13,85 @@ RAIN is an Arduino library for a rain sensor (analog). ## Description -A rain sensor is a relative simple device. +A rain sensor (FC-37, YL-83, HM-RD) is a relative simple device. It measures the resistance of a number of wires when these are put in a liquid (water) The device converts the resistance to a voltage typical 0 .. 5 Volt. -The more the wires are covered by the liquid, the higher the voltage. +The more the wires are covered by the liquid, the lower the voltage. +0.0 Volt is WET, and a high voltage is DRY. -The breakout I used to test also has a digital output, which goes HIGH if a certain -threshold (to be set with a potentiometer on the breakout) is reached. -The meaning / potential of this digital-out for the library needs to be investigated. +The breakout (LM393 comparator) I used to test also has a digital output, +which goes LOW if a threshold (to be set with a potentiometer on the breakout) is reached. The library is EXPERIMENTAL as it needs more testing. (changes of the interface are definitely possible). +## Hardware connection + +Typical connection + +``` + Processor LM393 SENSOR FC-37 + +-------------+ +----------+ +---------------------+ + | | | | | | + | GND |----->| GND | | | + | powerPin |----->| 5V |-----| | + | analogIn |<-----| AO | | | + | | | |-----| | + | digital in |<-----| DO | | | + | | | | | | + +-------------+ +----------+ +---------------------+ + +``` + ## Interface -- **RAIN(uint8_t port)** constructor. +- **RAIN(uint8_t port, uint8_t powerPin = 255)** constructor. port is the internal analog port to use. -- **bool begin(float maxVoltage, uint16_t maxSteps)** sets the ADC parameters. +powerPin is optional, but recommended. +- **bool begin(float maxVoltage, uint16_t maxSteps)** sets the ADC parameters. Allows to be changed runtime, e.g. if voltage fluctuates the math can be adapted by calling **begin()** again. Might be a separate **setVoltage()** is more efficient. - **float raw(uint8_t times = 1)** makes 1 or more measurements and averages them. returned value is the average number of ADC steps. - **float read(uint8_t times = 1)** makes 1 or more measurements, averages them and convert the average to a voltage. -THis voltage is returned, and also cached for **percentage()** and **getLevel()**. +This voltage is returned, and also cached for **percentage()** and **getLevel()**. + + +#### powerControl + +Will only work if the **powerPin** is set in the constructor. + +- **void powerOn()** switch the sensor on. +- **void powerOff()** switch the sensor off. + +The powerPin is used to switch the LM393 ON and OFF so the sensor is powered +only when the sensor is read. That reduces corrosion and energy usage. +Note: when the power is OFF, the digital-out cannot be used e.g. for interrupts. +So check what your project needs. + +Note: the powerOn() delays for 100us to give the LM393 time to stabilize. +Adjust this if needed. + #### Analysis +- **void setDryReference(float dryRef)** used to calibrate the voltage when the sensor is dry. +Use **read()** to read / calibrate the voltage when the sensor is dry. +If not explicitly set, the max ADC voltage os used. +- **void getDryReference()** returns the set value. - **float percentage()** returns the last **read()** to a percentage. Note one needs to call read() again to get a new value as this uses a cached value. - **float delta()** returns the delta voltage compared to previous read. It give the first derivative of the signal. How fast does it rise. -- **bool setLevel(uint8_t nr, uint16_t millivolts)** allows a user to set 5 voltage levels in milliVolts. +- **bool setLevel(uint8_t nr, uint16_t millivolts)** allows a user to set 4 voltage levels in milliVolts. - **uint8_t getLevel()** Returns the level of the current cached voltage. See example. -The library allows the user to set 5 thresholds or levels for the **getLevel()** function. -These 5 levels can help to control behaviour at a certain level. -Typical levels are almost empty, to almost full and full. +The library allows the user to set 4 thresholds or levels for the **getLevel()** function. +These 4 levels + 1 zero level can help to control behaviour of a system at a certain level. +Typical levels are almost empty, almost full and full. The level do not need to be on a linear mapping like 20% steps, if your project need other levels you can define these. @@ -68,7 +108,18 @@ See https://github.com/RobTillaart/MultiMap ## Operation -The examples show the basic working of the functions. +The examples show the basic working of the functions of the library. + +The rain sensor can be used in different types of projects. +Every project has a typical orientation of the sensor. + +| project | orientation | measurement | +|:-----------------|:----------------:|:-------------:| +| rain sensor | angle e.g. 45° | polling +| leak detection | horizontal | interrupt - digital OUT +| water level | vertical | polling + +For other applications it depends. ## Future @@ -76,19 +127,11 @@ The examples show the basic working of the functions. #### Must - update documentation - links etc. -- add interrupt example for digital output capture. #### Should - optimizations - - a lot of floats...==> more uint16_t millivolts? -- add examples. -- investigate possibilities of the digital output - - how to include - - example (see above) -- improve the **percentage()** maxVoltage setter? - - 2 different meanings of maxVoltage. For ADC and sensor out. - - is the device linear? does percentage make sense if it is not? + - a lot of floats...==> more uint16_t millivolts? (0.2.0) #### Could @@ -104,10 +147,11 @@ The examples show the basic working of the functions. - different salinity - different liquids? which? - how linear is the device? + + +#### Won't (unless requested) +- example with multiMap + - see multiMap library. - **incrLevel(nr, amount = 1)** + **decrLevel(nr, amount = 1)** to allow easier runtime tuning -#### Won't -- example with multiMap - - see multiMap library. - diff --git a/libraries/rain/examples/rain_delta/rain_delta.ino b/libraries/rain/examples/rain_delta/rain_delta.ino index 43caab27..afdf3861 100644 --- a/libraries/rain/examples/rain_delta/rain_delta.ino +++ b/libraries/rain/examples/rain_delta/rain_delta.ino @@ -3,6 +3,8 @@ // AUTHOR: Rob Tillaart // PURPOSE: demo read + delta // URL: https://github.com/RobTillaart/RAIN +// +// e.g. use with Arduino IDE plotter tool. #include "rain.h" diff --git a/libraries/rain/examples/rain_demo/rain_demo.ino b/libraries/rain/examples/rain_demo/rain_demo.ino index 4d5accd8..5a89d7a5 100644 --- a/libraries/rain/examples/rain_demo/rain_demo.ino +++ b/libraries/rain/examples/rain_demo/rain_demo.ino @@ -19,6 +19,9 @@ void setup() Serial.println("EXPERIMENTAL:"); RS.begin(5.000, 1023); + + // measured in an earlier run, adjust to your calibration. + RS.setDryReference(3.5); } @@ -33,3 +36,4 @@ void loop() // -- END OF FILE -- + diff --git a/libraries/rain/examples/rain_demo_powerpin/rain_demo_powerpin.ino b/libraries/rain/examples/rain_demo_powerpin/rain_demo_powerpin.ino new file mode 100644 index 00000000..3a2141df --- /dev/null +++ b/libraries/rain/examples/rain_demo_powerpin/rain_demo_powerpin.ino @@ -0,0 +1,38 @@ +// +// FILE: rain_demo_powerpin.ino +// AUTHOR: Rob Tillaart +// PURPOSE: demo read power pin +// URL: https://github.com/RobTillaart/RAIN + + +#include "rain.h" + +#define ANALOGPIN A0 +#define POWERPIN 7 + +RAIN RS(ANALOGPIN, POWERPIN); + +void setup() +{ + Serial.begin(115200); + while (!Serial); + Serial.println(__FILE__); + Serial.print("RAIN_LIB_VERSION: "); + Serial.println(RAIN_LIB_VERSION); + Serial.println("EXPERIMENTAL:"); + + RS.begin(5.000, 1023); +} + + +void loop() +{ + Serial.print(RS.read(), 3); + Serial.print('\t'); + Serial.print(RS.percentage(), 1); + Serial.print('\n'); + delay(100); +} + + +// -- END OF FILE -- diff --git a/libraries/rain/examples/rain_digital_out/rain_digital_out.ino b/libraries/rain/examples/rain_digital_out/rain_digital_out.ino new file mode 100644 index 00000000..a2e68589 --- /dev/null +++ b/libraries/rain/examples/rain_digital_out/rain_digital_out.ino @@ -0,0 +1,48 @@ +// +// FILE: rain_digital_out.ino +// AUTHOR: Rob Tillaart +// PURPOSE: demo digital out DO pin +// URL: https://github.com/RobTillaart/RAIN + + +#include "rain.h" + +#define ANALOGPIN A0 +#define POWERPIN 7 +#define DIGIOUT 8 + +RAIN RS(ANALOGPIN, POWERPIN); + + +void setup() +{ + Serial.begin(115200); + while (!Serial); + Serial.println(__FILE__); + Serial.print("RAIN_LIB_VERSION: "); + Serial.println(RAIN_LIB_VERSION); + Serial.println("EXPERIMENTAL:"); + + RS.begin(5.000, 1023); + + pinMode(DIGIOUT, INPUT_PULLUP); +} + + +void loop() +{ + if (digitalRead(DIGIOUT) == LOW) + { + Serial.print(millis()); + Serial.print('\t'); + Serial.print(RS.read(), 3); + Serial.print('\t'); + Serial.print(RS.getLevel()); + Serial.print('\n'); + } + delay(100); + // other code here +} + + +// -- END OF FILE -- diff --git a/libraries/rain/examples/rain_interrupt/rain_interrupt.ino b/libraries/rain/examples/rain_interrupt/rain_interrupt.ino new file mode 100644 index 00000000..4112a849 --- /dev/null +++ b/libraries/rain/examples/rain_interrupt/rain_interrupt.ino @@ -0,0 +1,57 @@ +// +// FILE: rain_interrupt.ino +// AUTHOR: Rob Tillaart +// PURPOSE: demo rain_interrupt digital out +// URL: https://github.com/RobTillaart/RAIN + + +#include "rain.h" + +#define ANALOGPIN A0 +#define POWERPIN 7 +#define DIGIOUT_IRQ 2 + +RAIN RS(ANALOGPIN, POWERPIN); + +volatile bool waterDetected = false; + + +void setup() +{ + Serial.begin(115200); + while (!Serial); + Serial.println(__FILE__); + Serial.print("RAIN_LIB_VERSION: "); + Serial.println(RAIN_LIB_VERSION); + Serial.println("EXPERIMENTAL:"); + + RS.begin(5.000, 1023); + + attachInterrupt(digitalPinToInterrupt(DIGIOUT_IRQ), isr, FALLING); +} + + +void loop() +{ + if (waterDetected) + { + Serial.print(millis()); + Serial.print('\t'); + Serial.print(RS.read(), 3); + Serial.print('\t'); + Serial.print(RS.getLevel()); + Serial.print('\n'); + waterDetected = false; + } + delay(100); + // other code here +} + + +void isr() +{ + waterDetected = true; +} + + +// -- END OF FILE -- diff --git a/libraries/rain/examples/rain_setLevel_guard_low/rain_setLevel_guard_low.ino b/libraries/rain/examples/rain_setLevel_guard_low/rain_setLevel_guard_low.ino index 5f0edc86..9675fb7e 100644 --- a/libraries/rain/examples/rain_setLevel_guard_low/rain_setLevel_guard_low.ino +++ b/libraries/rain/examples/rain_setLevel_guard_low/rain_setLevel_guard_low.ino @@ -46,14 +46,14 @@ void loop() int level = RS.getLevel(); switch (level) { - case 4: + case 0: // max WET if (prevLevel != level) { Serial.println("Pump speed 100%"); } analogWrite(PUMP_PIN, 255); break; - case 3: + case 1: if (prevLevel != level) { Serial.println("Pump speed 90%"); @@ -65,20 +65,20 @@ void loop() { Serial.println("Pump speed 75%"); } - analogWrite(PUMP_PIN, 195); // ~75% + analogWrite(PUMP_PIN, 195); break; - case 1: + case 3: if (prevLevel != level) { - Serial.println("Start pumping"); + Serial.println("Pump speed 50%"); } - analogWrite(PUMP_PIN, 130); // ~50% + analogWrite(PUMP_PIN, 130); break; - case 0: + case 4: // DRY default: if (prevLevel != level) { - Serial.println("Stop pumping"); + Serial.println("Stopped pumping"); } analogWrite(PUMP_PIN, 0); break; @@ -88,4 +88,4 @@ void loop() } -// -- END OF FILE -- +// -- END OF FILE -- diff --git a/libraries/rain/keywords.txt b/libraries/rain/keywords.txt index c3507b86..bc114ded 100644 --- a/libraries/rain/keywords.txt +++ b/libraries/rain/keywords.txt @@ -8,10 +8,18 @@ begin KEYWORD2 raw KEYWORD2 read KEYWORD2 +setDryReference KEYWORD2 +getDryReference KEYWORD2 + percentage KEYWORD2 +delta KEYWORD2 + setLevel KEYWORD2 getLevel KEYWORD2 +powerOn KEYWORD2 +powerOff KEYWORD2 + # Constants (LITERAL1) RAIN_LIB_VERSION LITERAL1 diff --git a/libraries/rain/library.json b/libraries/rain/library.json index e8352f7f..d8855719 100644 --- a/libraries/rain/library.json +++ b/libraries/rain/library.json @@ -1,7 +1,7 @@ { "name": "RAIN", - "keywords": "RAIN, wet", - "description": "Arduino library for rain sensor. (analog)", + "keywords": "RAIN, wet, FC-37, YL-83, HM-RD, LM393", + "description": "Arduino library for FC-37 analog rain sensor and compatibles.", "authors": [ { @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/RAIN.git" }, - "version": "0.1.1", + "version": "0.1.2", "license": "MIT", "frameworks": "arduino", "platforms": "*", diff --git a/libraries/rain/library.properties b/libraries/rain/library.properties index 044f5a51..809adfe4 100644 --- a/libraries/rain/library.properties +++ b/libraries/rain/library.properties @@ -1,10 +1,10 @@ name=RAIN -version=0.1.1 +version=0.1.2 author=Rob Tillaart maintainer=Rob Tillaart -sentence=Arduino library for rain sensor (analog). -paragraph=wet, wetness. -category=Signal Input/Output +sentence=Arduino library for FC-37 analog rain sensor and compatibles. +paragraph=wet, wetness, FC-37, YL-83, HM-RD, LM393. +category=Sensors url=https://github.com/RobTillaart/RAIN architectures=* includes=rain.h diff --git a/libraries/rain/rain.cpp b/libraries/rain/rain.cpp index 6f7d0447..7de8b01a 100644 --- a/libraries/rain/rain.cpp +++ b/libraries/rain/rain.cpp @@ -1,7 +1,7 @@ // // FILE: rain.cpp // AUTHOR: Rob Tillaart -// VERSION: 0.1.1 +// VERSION: 0.1.2 // DATE: 2021-12-03 // PURPOSE: Arduino library for a rain sensor // URL: https://github.com/RobTillaart/RAIN @@ -10,19 +10,28 @@ #include "rain.h" -RAIN::RAIN(uint8_t port) +RAIN::RAIN(uint8_t port, uint8_t powerPin) { _port = port; + _powerPin = powerPin; _maxVoltage = 5; _maxSteps = 1023; + _dryRefVoltage = _maxVoltage; } bool RAIN::begin(float maxVoltage, uint16_t maxSteps) { - _maxVoltage = maxVoltage; - _maxSteps = maxSteps; - _mVstep = _maxVoltage / _maxSteps; + _maxVoltage = maxVoltage; + _maxSteps = maxSteps; + _mVstep = _maxVoltage / _maxSteps; + _dryRefVoltage = _maxVoltage; + + if (_powerPin != 255) + { + pinMode(_powerPin, OUTPUT); + powerOn(); + } read(); return true; } @@ -32,10 +41,14 @@ float RAIN::raw(uint8_t times) { if (times == 0) times = 1; float sum = 0; + + powerOn(); for (int i = 0; i < times; i++) { sum += analogRead(_port); } + powerOff(); + if (times > 1) sum /= times; return sum; } @@ -49,9 +62,23 @@ float RAIN::read(uint8_t times) } +void RAIN::setDryReference(float dryRef) +{ + _dryRefVoltage = dryRef; +} + + +float RAIN::getDryReference() +{ + return _dryRefVoltage; +} + + float RAIN::percentage() { - return _voltage * 100.0 / _maxVoltage; + float p = 100.0 - (_voltage * 100.0 / _dryRefVoltage); + if (p < 0) p = 0; + return p; } @@ -81,5 +108,24 @@ uint8_t RAIN::getLevel() } +void RAIN::powerOn() +{ + if (_powerPin != 255) + { + digitalWrite(_powerPin, HIGH); + delayMicroseconds(100); // time to stabilize, adjust if needed. + } +} + + +void RAIN::powerOff() +{ + if (_powerPin != 255) + { + digitalWrite(_powerPin, LOW); + } +} + + // -- END OF FILE -- diff --git a/libraries/rain/rain.h b/libraries/rain/rain.h index 90f33106..6d1d6bab 100644 --- a/libraries/rain/rain.h +++ b/libraries/rain/rain.h @@ -2,7 +2,7 @@ // // FILE: rain.h // AUTHOR: Rob Tillaart -// VERSION: 0.1.0 +// VERSION: 0.1.2 // DATE: 2022-11-23 // PURPOSE: Arduino library for rain sensor (analog). // URL: https://github.com/RobTillaart/RAIN @@ -12,13 +12,15 @@ #include "Arduino.h" -#define RAIN_LIB_VERSION (F("0.1.0")) +#define RAIN_LIB_VERSION (F("0.1.2")) class RAIN { public: - RAIN(uint8_t port); + // port = analogPort, + // powerPin is optional, 255 == not used => see readme.md + RAIN(uint8_t port, uint8_t powerPin = 255); // set the ADC parameters // can be changed runtime, e.g if voltage fluctuates. @@ -27,29 +29,45 @@ public: // returns steps float raw(uint8_t times = 1); // returns voltage + // the lower the voltage the wetter. float read(uint8_t times = 1); // ANALYSIS - // returns last read value as percentage of maxVoltage. - // indicating wetness? - // it assumes / implies linear behaviour + // read the sensor when it is dry to get a reference (calibration). + // will be used by percentage(), can be used to setLevel(). + void setDryReference(float dryRef); + float getDryReference(); + + // returns last read value as percentage of DryReference (if set). + // indicating wetness 0 == DRY 100 == WET + // percentage assumes / implies "linear" behaviour float percentage(); + + // delta with respect to previous read(). float delta(); - // level = 1..4 (level 0 == 0 Volt) + // level = 1..4 + // level 0 == 0 Volt ==> WET) + // level 4 ==> DRY // user is responsible that values are increasing voltages. bool setLevel(uint8_t nr, uint16_t milliVolts); uint8_t getLevel(); + // will only work when set in constructor. + void powerOn(); + void powerOff(); + private: uint8_t _port; + uint8_t _powerPin = 255; // 255 means not set. float _maxVoltage; uint16_t _maxSteps; float _mVstep; float _voltage; + float _dryRefVoltage; float _previous; uint16_t _level[5] = { 0, 1000, 2000, 3000, 4000 }; // millivolts };