Translate

Saturday, 24 May 2014

Arduino dehumidifier controller project - Wireless update!

Some spare time over the weekend means I can finally crack on with this!

After experimenting with a number of methods of sending and receiving data, I came across the virtualwire library here: http://www.airspayce.com/mikem/arduino/VirtualWire/

Now, there's a few things to note. Whilst surfing the various boards, there's talk of virtualwire only being able to send characters, which makes sending an integer a bit of a bind. There's people doing itoa's and atoi's back again. What happens if you need to send multiple values like we do? Temperature, humidity etc? We'll have to sync the transmitter and receiver for the first time... then what happens if a packet is dropped? It was all a bit much really, and sending integers as character arrays was all a bit wasteful of bandwidth. 

Now virtualwire is great, it takes care of manchester coding your data, and provides a bit of pre-amble so your simple receiver can sort out it's agc before outputing data. It's data is defined as uint_8 .... hang on ... that's a byte isn't it? So why can't I send an integer? It's just data ... 

So, pencil and pad at the ready, and a bit of a read about struct in by big book of C and we can create a custom message, with a unique identifier (just in case someone rings my wireless doorbell or my wireless weather station happens to transmit at the same time and corrupts our message, or indeed preventing our receiver attempting to decode such a message!)

For testing purposes, the two arduinos (arduini?) were linked by a bit of wire instead of the RF link. (Connect your output pin to the input, and link the grounds.)

Data rate during testing was 2000 bits per second.
Once the RF link was added I reduced this to 300 bits per second to make the link a little more robust.

Even reducing the data rate to 300 bits left me with woeful range, so I investigated. Output from the transmitter seemed good on the spectrum analyser, on frequency and plenty of output. 
Output from the receiver was noisy and it appeared the receiver was particularly "deaf". 
I used a frequency source to sweep the receiver, to see if it was tuned in accurately, my thinking being there's a nice big coil on the top to tweak! Sweeping the tuner found it tuned to 315MHz! Great. A 433 TX and a 315 RX. It was amazing it worked at all on the bench! Thankfully the supplier has agreed to send me out a new set, so hopefully It'll be wireless soon enough! 

Here's the transmitter code:-



// 
// FILE:  wireless_dehumid.pde
// Written by Andy Doswell 24th May 2014
// PURPOSE: DHT11 sensor with LCD Display and output for controlling dehumidifier.
// Data send via virtualwire and 433MHZ link to remote display
// Dehumidifier is controlled by a relay attached to pin 7, defined in rlyPin.
// DHT11 sensor is connected to 8, as defined in #define
// LCD is a Hitachi HD44780 or compatible, attached thus:
// LCD RS pin to digital pin 12
// LCD Enable pin to digital pin 11
// LCD D4 pin to digital pin 5
// LCD D5 pin to digital pin 4
// LCD D6 pin to digital pin 3
// LCD D7 pin to digital pin 2
// RW to GND
// V0 Held high (this may or may not work with your LCD, usual practice is to connect this to a 10K pot between +5 and GND)
// TX connected to pin 10
// delta max = 0.6544 wrt dewPoint()
// 6.9 x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
double dewPointFast(double celsius, double humidity)
{
 double a = 17.271;
 double b = 237.7;
 double temp = (a * celsius) / (b + celsius) + log(humidity*0.01);
 double Td = (b * temp) / (a - temp);
 return Td;
}

#include <VirtualWire.h>
#include <VirtualWire_Config.h>

#include <dht.h>

dht DHT;

#define DHT11_PIN 8

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// define constants & global variables
const int rlyPin = 7; //defines pin the relay is connected to. relay is active low
const int TimerLength = 1800;// number of seconds in an hour / 2 - this sets the minimum time the dehumidifier will remain on for.
int Timer = 0; //timer is off to start
boolean DewFlag = false; // This is the dew flag. Off as default.
boolean OutputStatus = false; //Output status is off as default

// Data structure set up for Transmission

struct TXData
{
  int TX_ID;
  int Temp;
  int Humidity;
  int Dew;
  boolean Output;
};
  

void setup()
{
  lcd.begin(16, 2); // defines the LCD as a 16 x 2
  pinMode (rlyPin, OUTPUT); // sets our relay pin
  digitalWrite (rlyPin, HIGH); // sets the relay off for default condition.
  
  // Virtualwire setup
  vw_set_tx_pin(10); // TX pin set to 10
  vw_set_rx_pin(9); // RX pin set to a spare pin, even though we don't use it. If left as default it interferes with LCD operation.
  vw_setup(300); //sets virtualwire for a tx rate of 300 bits per second
  

}

void loop()
{
  int chk = DHT.read11(DHT11_PIN); // these 4 lines get data from the sensor
  int Dew = dewPointFast(DHT.temperature, DHT.humidity);
  int Temp = (DHT.temperature);
  int Humidity = (DHT.humidity);
  int DewTrip= Dew + 5; // Brings the dehumidifier on 5 deg C before the dew point. 
  
// writes information about the system to the LCD
  lcd.clear ();
  lcd.print("Humidity:");
  lcd.print(Humidity);
  lcd.print("%");
  lcd.setCursor(0, 1);
  lcd.print(Temp);
  lcd.print((char)0xDF);
  lcd.print("C");
  lcd.setCursor(6, 1);
  lcd.print("Dew:");
  lcd.print(Dew);
  lcd.print((char)0xDF);
  lcd.print("C");
  
  struct TXData payload; //Loads the Data struct with the payload data
  
  payload.TX_ID=10;
  payload.Temp = Temp;
  payload.Humidity = Humidity;
  payload.Dew = Dew;
  payload.Output = OutputStatus;
  
  vw_send((uint8_t *)&payload, sizeof(payload)); //Transmits the struct
  vw_wait_tx(); //waits for the TX to complete
  
// Dew detect loop. If the dewTrip point is reached, start the timer running and set the Dew flag
  if ( Temp <= DewTrip ) {
    DewFlag = true;
    Timer = 1;       
  } 
  else {
    DewFlag = false;
}

  
  if (Timer >= TimerLength and DewFlag == false) { // If the timer has expired and there's no dew, switch the dehumidifier off.
    Timer = 0;
    digitalWrite (rlyPin, HIGH);
   
  }

  if (Timer !=0) {                // If the timer is running, switch the dehumidifier on , and write On to the lcd.
    digitalWrite (rlyPin, LOW);
    lcd.setCursor (13,0);
    lcd.print (" On");
    OutputStatus = true;
    Timer++;
  }
  
 else {
   lcd.setCursor (13,0);
    lcd.print ("off");
    OutputStatus = false;
 }
  
 delay (2000);

}
//
// END OF FILE
//





and the receiver code:-




// Receiver Sketch for Dehumidifier controller project
// Written by A.G.Doswell 23 May 2014
// LCD is a Hitachi HD44780 or compatible, attached thus:
// LCD RS pin to digital pin 12
// LCD Enable pin to digital pin 11
// LCD D4 pin to digital pin 5
// LCD D5 pin to digital pin 4
// LCD D6 pin to digital pin 3
// LCD D7 pin to digital pin 2
// RW to GND
// V0 Held high (this may or may not work with your LCD, usual practice is to connect this to a 10K pot between +5 and GND)
// Receiver connected to pin 9


#include <VirtualWire.h>
#include <VirtualWire_Config.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int TX_ID =10;
int Temp;
int Humidity;
int Dew;
boolean Output;



void setup() {
              lcd.begin (16, 2);
              // Virtualwire setup
              vw_set_tx_pin(10); // Even though it's not used, we'll define it so the default doesn't interfere with the LCD library.
              vw_set_rx_pin(9); // RX pin set to pin 9
              vw_setup(300); //sets virtualwire for a tx rate of 300 bits per second, nice and slow! 
              vw_rx_start();     
              }  
void loop()
{
typedef struct rxRemoteData //Defines the received data, this is the same as the TX struct
{
int    TX_ID; 
int    Temp;   
int    Humidity;
int    Dew;
boolean Output;
};

struct rxRemoteData receivedData;
uint8_t rcvdSize = sizeof(receivedData);

if (vw_get_message((uint8_t *)&receivedData, &rcvdSize)) 
{
  if (receivedData.TX_ID == 10)     { //Only if the TX_ID=10 do we process the data.
    lcd.setCursor(13,0);
    lcd.print (" Rx");
    delay (100);
    int TX_ID = receivedData.TX_ID;
    int Temp = receivedData.Temp;
    int Humidity = receivedData.Humidity;
    int Dew = receivedData.Dew;
    boolean Output = receivedData.Output;
    
        
      // writes the received data to the LCD
  lcd.clear ();
  lcd.print("Humidity:");
  lcd.print(Humidity);
  lcd.print("%");
  lcd.setCursor(0, 1);
  lcd.print(Temp);
  lcd.print((char)0xDF);
  lcd.print("C");
  lcd.setCursor(6, 1);
  lcd.print("Dew:");
  lcd.print(Dew);
  lcd.print((char)0xDF);
  lcd.print("C");
  
  if (Output == true) {
      lcd.setCursor (13,0);
      lcd.print (" On");
    
  }
     else {
       lcd.setCursor (13,0);
       lcd.print ("off");

           }
  
      } 

  }
}

// End of file

Let me know if this has been of any use...  but for now I have a nice dry loft!

6 comments:

  1. Thank you very much. That was very helpful

    ReplyDelete
    Replies
    1. Thanks Ecafe! Do you have any pictures to share?

      Delete
  2. Hi Andy,
    I am building aquaponics control and monitoring system. As of now I do not have nice pictures to show you. But once I have any I will post.
    Thanks again

    ReplyDelete
  3. I made a minor update ! http://andydoz.blogspot.com/2015/09/minor-dht22-dehumidifier-controller.html

    ReplyDelete
  4. Wow what a great project. Thanks for the code as I am building something very similar for an indoor grow project. Want to keep my humidity and temperature controlled automatically cause tomatoes grow better in ideal conditions. Thank you for all this great information and such a detailed post. Very creative indeed, my wife agrees with me on that one.

    Brian Hopkins @ Microtips USA

    ReplyDelete
  5. Hey Brian,

    Thanks for the comment. Should be a piece of cake to add another relay in to control a heater to make thermostat. I'm currently considering a PID controller project to control water temperature. Watch this space !

    ReplyDelete