Introduction
I am always aware of the relative humidity in our bathroom. Recently we bought an air dryer, but I was very dissatisfied by the on-off cycles of this stupid device. Although I set it to 70 or 80% RH, it switches on for very short periods and (at times) I did not see this high humidity. I am already driving a network of wireless sensors within the 433MHz band and fill a database with the readings of three sensors. I added one more using one Arduino Uno R3 with a DHT22 sensor and a 433MHz transmitter so I could track the temperature and humidity values of the bath too.
In general, controlling humidity cannot be done simply by watching for the current RH% and then switch on or off a dryer or fan. RH% will vary with temperature changes and depends on the outside humidity. For example, you will not reach 50% relative humidity (RH) in a room if the outside has 75% RH and the room is not sealed.
I decided to control the air dryer from the Arduino with some better logic than just going on/off at a specific humidity level.
Background
When showering starts in the bathroom, the humidity rapidly grows. I would like the Arduino to recognize this peak change and to switch the dryer on for the maximum time.
As the Arduino was already equipped with the 433MHz transmitter and there are power switches that are also controlled by 433MHz and I would like to avoid any contact with high voltage, I decided to control the power from the same transmitter.
So we have the Arduino, a DHT22 (the DHT11 was too bad), and a 433 MHz receiver. For some visual feedback I added an LCD, but it is not needed for the function.
Using the Code
The code uses two buffers to store the recent humidity measurements. Only the last values are kept. Every time a new value is pushed, the oldest value is removed. I use one 'short-time' buffer, which is updated every minute. The second buffer is the long-time buffer (memory), which is filled every time when the buffer capacity of the first buffer is reached. So let's say I store five values in the first buffer, then the second buffer is updated on every fifth update.
If the newest value is above a threshold of the last one and the values are increasing, I set a state flag which represents the powering of the dryer. The second buffer is currently not used but would be useful to switch the dryer off when the humidity is below the normal long-time values.
I have implemented a base class (using code of circular buffer) and init
two of these buffer classes in my new class.
ByteBuffer.h (a 'stack' like buffer):
#include <stdlib.h>
#ifndef BYTEBUFFER_H
#define BYTEBUFFER_H
#define byte unsigned char
class ByteBuffer
{
public:
ByteBuffer();
void init(unsigned int buf_size);
void clear();
void deAllocate();
int getSize();
int getCapacity();
byte peek(unsigned int index);
int putInFront(byte in);
int put(byte in);
int push(byte in); byte getMedian(); byte getMax(); byte getMin(); byte getState(); void setTreshold(byte t); byte getTreshold(); int getDirection();
int getStateDuration();
int putIntInFront(int in);
int putInt(int in);
int putLongInFront(long in);
int putLong(long in);
int putFloatInFront(float in);
int putFloat(float in);
byte get();
byte getFromBack();
int getInt();
int getIntFromBack();
long getLong();
long getLongFromBack();
float getFloat();
float getFloatFromBack();
void setMaxDuration(int);
protected:
byte* data;
unsigned int capacity;
unsigned int position;
unsigned int length;
byte state;
byte treshold;
int stateDuration; int maxDuration; int direction;
};
#endif // BYTEBUFFER_H
This class is used two times for a long and short time storage in NewBuffer
:
#ifndef NEWBUFFER_H
#define NEWBUFFER_H
#include "ByteBuffer.h"
class newBuffer
{
public:
newBuffer();
~newBuffer();
void init(int s);
ByteBuffer bytebuffer1;
ByteBuffer bytebuffer2;
byte peek1(unsigned int index);
byte peek2(unsigned int index);
int getSize1();
int getSize2();
byte getMedian1(); byte getMax1(); byte getMin1(); byte getState1(); byte getTreshold1();
byte getMedian2(); byte getMax2(); byte getMin2(); byte getState2(); void setTreshold(byte t); byte getTreshold2();
int getDirection1();
int getStateDuration1();
int getDirection2();
int getStateDuration2();
void setMaxDuration1(int);
void setMaxDuration2(int);
int put(byte in);
int push(byte);
protected:
int iCount;
byte treshold;
int capacity;
int maxDuration; private:
};
#endif // NEWBUFFER_H
You see there are getters to get values from the short and the long time buffer.
The main work is done when a new value is pushed to the stack:
int newBuffer::push(byte in){
iCount++;
bytebuffer1.push(in);
if(iCount==capacity){
bytebuffer2.push(in);
iCount=0;
}
return 0;
}
You see that the second (long time) buffer gets a push only every x times.
The Arduino sketch:
...
void setup(){
Serial.begin(SERIAL_BAUD);
Serial.println("ThermoHygroTransmitter version 4 (power save 2)");
sensor.setup(DHT_DATA_PIN);
sleepTime=10000;
pinMode(lcd_backlight, OUTPUT);
lcd.begin(16, 2);
lcd.print("Temp/Feuchte"); lcdON();
send_buffer.init(5);
send_buffer.setTreshold(5);
send_buffer.setMaxDuration1(10);
mySwitch = RCSwitch();
mySwitch.enableTransmit(TX_DATA_PIN);
mySwitch.setProtocol(1);
switchOnOff(false);
}
void loop(){
animateLCD();
Serial.println("...waked up");
float humidity = sensor.getHumidity();
float temperature = sensor.getTemperature();
if(strcmp(sensor.getStatusString(),"OK")==0){
bValidData=true;
lastTemp=(int)temperature;
lastHumi=(int)humidity;
showLCD(lastTemp, lastHumi, send_buffer.getState1());
}
else{
bValidData=false;
}
Serial.print("sendCount="); Serial.println(sendCount);
if(sendCount >= sendInterval){
sendCount=0;
if(bValidData) {
send_buffer.push((byte)lastHumi);
state=send_buffer.getState1();
if(state==0)
switchOnOff(false);
else
switchOnOff(true);
int x=0;
Serial.println("============================");
for(x=0; x<send_buffer.getSize1(); x++){
Serial.print("[");
Serial.print(send_buffer.peek1(x));
Serial.print("]");
}
Serial.println("\n============================");
if(state==1)
transmitter.sendTempHumi(lastTemp * 10 + 5, lastHumi);
else
transmitter.sendTempHumi(lastTemp * 10, lastHumi);
Serial.println("Transmit done");
blinkLEDfast();
bValidData=false;
showLCD(lastTemp, lastHumi, state);
} } sendCount++;
blinkLED();
Serial.println("About to sleep...");
delay(200);
sleep.pwrDownMode(); sleep.sleepDelay(sleepTime); }
Here is the push of the new measured RH value and the check of the state
property to switch an outlet on/off:
send_buffer.push((byte)lastHumi);
state=send_buffer.getState1();
if(state==0)
switchOnOff(false);
else
switchOnOff(true);
When a new value is pushed, we do some calculations and start/continue the powering of a dryer fan using the state
var:
int ByteBuffer::push(byte in){
if(length < capacity){
data[(position+length) % capacity] = in;
length++;
}
else{
unsigned int i=0;
for(i=0; i<length-1; i++)
data[i]=data[i+1];
data[length-1]=in;
}
if( ((getMax()-getMin())>treshold) && (getDirection()>0) ){
if(stateDuration<maxDuration){
state=1;
}
}
if(state==1 || stateDuration>0)
stateDuration++; if(stateDuration>maxDuration){
if(state==1){
state=0;
}
stateDuration=0;
}
return 0;
}
The above code first pushes the new value onto the stack. If the stack is full in regards of the number of maximum values, the oldest value is removed.
Then we check if max and min of all values is greater than a threshold and if the value shows an increase. If so, we start to set the state
var. The state
var is used to control the powering of a dryer fan and will remain set for maxDuration
push cycles. So we do not switch on/off the fan directly pending to the values but implement a follow-up time. As we push a new value every minute and maxDusration
is 9
, we have a follow-up time of 9 minutes.
As I log (send) all values to a php/mysql web server, I can control what the sketch does:
As you see, the state powered the outlet three times, every time the threshold of the humidity increase was hit. We are three people showering at the morning. ;-)
Currently I am using a netio board (Pollin.de) to receive temperature and humidty of wireless sensors and forward the data to a web server that can produce above graphics.
This netio board is connected via ethernet and receives the wireless sensors with a simple 433MHz receiver:
Acknowledements
ToDo
- Cleanup unused code from
ByteBuffer
and newBuffer