Standalone damp wall warner (complete) - ATtiny13 with Sleepmode (MegaOhmMeter)

Costs:
< 2 Euro if you are using ic-sockets for soldering the components together
(like here http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/)

Used Sensor (Homemade):
http://forum.arduino.cc//index.php?topic=195258.msg1441018#msg1441018

Resistors for the LEDs are not needed when using <=3V.

Programing:
You need to know how to program an ATtiny with an Arduino or ISP-Programmer
http://forum.arduino.cc//index.php?topic=194184.msg1434240#msg1434240

/*
//************************************************
  *  Damp/Wet Wall detector with ATtiny13a and two LED
  *  by Enam
  *  no warrantys or guarantees at all
//***********************************************

 ATtiny13 8Pin Pins:
 
 //                 	 +-\/-+
 //Reset ADC0 (D 5) PB5 1|    |8 Vcc
 // 	 ADC3 (D 3) PB3 2|    |7 PB2 (D 2) ADC1
 // 	 ADC2 (D 4) PB4 3|    |6 PB1 (D 1) PWM1
 //       	    GND 4|    |5 PB0 (D 0) PWM0
 //              	 +----+
 
 
 
 Program objective:
 
 Wet Wall Alarm (Red LED flashing, quicker if more damp) if moisture is to high and condenses at the wall
 (dewpoint / broken "tube")


 
 
 Hardware/Pins:
 
 3Volt Batterie  (2-2,7V with 2x "ready2use" NIMH rechargable Batteries)
 
 Voltagedivider between
 two pins in the wall (Rwall) (D1)  (>30M dry  22,5-30M=ok  <22,5M Wet) 
 and 20MOhm (D0)
 sensing with (D2)
 
 Outputpins (D0, D1)are toggling for squarewave AC
 to prevent corrosive layers increasing resistance of the pins.
  
 D3  Red LED (to GND)
 D4 Green LED (to GND)
 
 D2 /AD1 = ADC in
 D1 = toggle output pinA
 D0 = toggle output pinB
 
 Program:
 
 Part1:
 Outputpins on 
 (a high, b low)
 read adc
 
 to have same amount of time used in both parts:
 do as if writing to led, write 0
 sleep as in part2
 
 Part2:
 toggle output pins
 (a low, b high)
 
 read adc ()
 blink very slow green when dry (to see its working at all), quicker when getting weter
 blink red when too wet 
 sleep in LED on time
 sleep in LED off time (up to 8 sec)
 
 
 
 Mainparts of the "sleep" code are from Lab3, Academy of Media Arts Cologne "Nightingale" and "elabz"
 http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
 http://www.elabz.com/attiny13-12-led-blinker-with-motion-detection-and-scripted-blinks/
 
 
 
 Todo:
  Trafficlight LED
 
 // Green Red
// 3 Areas: dry normal wet
 //   >30M   <30->22,5  <22,5 = G GR R
 //       613             541 (not 460)
 
 
 // Green Yellow Red with 3Led on 2Pins+Supply
 //5 Areas: dry -- normal normalwet wet -- wetwet
 //   100-30M   30-22,5  22,5-15 15-7,5  7,5-0 = G GY Y YR R
 */






//################# for Sleep ##########
#include <avr/sleep.h> // sleep code by insidegadgets.com
volatile boolean f_wdt=1;
//#####################################

//Variable  Sensor
int Sensorval=0;
int delayforsleep=0;

//Led Pins
byte LedRedPin=3;
byte LedGreenPin=4;

//Output Pins (toggle pins)
byte APin=1;
byte BPin=0;

//Sens Pin (ADC1)
byte ADCPin=A1;

// Defining state of wetness in ADC Values, calculated by voltage divider resitances of wall
int dry=613; // 
//int normalw=292; // not nedded
int wet=541; // not 460          


void setup()
{
  pinMode(LedRedPin, OUTPUT); // 
  pinMode(LedGreenPin, OUTPUT); // 


  pinMode(ADCPin, INPUT); //
  pinMode(APin, OUTPUT); // 
  pinMode(BPin, OUTPUT); // 



  //#######################for Sleep, part void setup()
  //from http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
  // CPU Sleep Modes 
  // SM2 SM1 SM0 Sleep Mode
  // 0    0  0 Idle
  // 0    0  1 ADC Noise Reduction
  // 0    1  0 Power-down
  // 0    1  1 Power-save
  // 1    0  0 Reserved
  // 1    0  1 Reserved
  // 1    1  0 Standby(1)

  /*
cbi( MCUCR,SE );      // sleep enable, power down mode
   cbi( MCUCR,SM0 );     // power down mode
   sbi( MCUCR,SM1 );     // power down mode
   cbi( MCUCR,SM2 );     // power down mode
   */
  // from http://elabz.com/attiny13-12-led-blinker-with-motion-detection-and-scripted-blinks/
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
  //##############################################
}


void loop()
{
  // -------  Part1, result not displayed on leds, but both parts should need same amount of time 
  // use same prg as part2 for same amount of time, but dont light leds
  // values would be "wrong", because of inverted voltage supply compared to part2
  // The lower wetness, the higher delaytime for blinking (saving energy by blinkin seldom,see its working, )

  // Output pins on a=high b=low
  digitalWrite(APin,1);
  digitalWrite(BPin,0);
  sleepuntil(0);
  analogRead (ADCPin);
  show(0);


  //  -----Part2, 

  digitalWrite(APin,0);
  digitalWrite(BPin,1);
  sleepuntil(0);
  Sensorval = analogRead (ADCPin);
  show(1);
}



//------- subprg show(), tell it if leds should show result or not with show(1); or  show(0); in void loop
void show(int onoff)
{
  // Trafficlight
  //   >30M   <30->22,5  <22,5 = G GR R
  //  dry=613            wet=460
  // Lits GR together from 22.5 tro 30MOhm

  if (Sensorval <= dry)  
  {
    digitalWrite(LedRedPin, onoff);
  }

  if (Sensorval >= wet)
  { 
    digitalWrite(LedGreenPin,onoff);
  }

  /// on-time with sleep
   sleepuntil(0);

  
  digitalWrite(LedGreenPin,0);
  digitalWrite(LedRedPin, 0);  
  // The lower wetness (dryer), the higher delaytime for blinking (saving energy by blinkin seldom,see its working, )
  
  //calc delay for sleep
  delayforsleep= Sensorval/113;  
  //sleepuntil() knows only 0-9 different delay times 
  //1023/123=9.... 126/127=0...
  
  sleepuntil(delayforsleep);
  // 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
  // 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
}


//#################Sleep Subprgs######################
// Call for sleep
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void sleepuntil(int timer)
{
  setup_watchdog(timer);
  system_sleep();
}

// From http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
//****************************************************************  
// set system into the sleep state 
// system wakes up when watchdog is timed out
void system_sleep()
{
  cbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter OFF

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
  sleep_enable();

  sleep_mode();                        // System sleeps here

    sleep_disable();                     // System continues execution here when watchdog timed out 
  sbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter ON
}

//****************************************************************
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(int ii)
{
  byte bb;

  if (ii > 9 ) ii=9;
  bb=ii & 7;
  if (ii > 7) bb|= (1<<5);
  bb|= (1<<WDCE);

  MCUSR &= ~(1<<WDRF);
  // start timed sequence
  WDTCR |= (1<<WDCE) | (1<<WDE);
  // set new watchdog timeout value
  WDTCR = bb;
  //---------- WDTIE instead of  WDIE (Datasheet Attiny page42)
  WDTCR |= _BV(WDTIE); 
}

//****************************************************************  
// Watchdog Interrupt Service / is executed when  watchdog timed out
ISR(WDT_vect)
{
  f_wdt=1;  // set global flag
}
//##########################################################

Kind Regards
Enam

Any advice for improving / correcting mistakes is welcome!

If it is of any Interest, I can give advice how the code should work also on Arduino with an ATmega168/328.

The formula to make an real MegaOhmmeter with a bigger uC should be
Runknown=1/(1024/Sensorval-1)*20, where 20 is the value of the known resistor, here 20MOhm. HCS

Enam

Around 500 views and no comment?

Any advice / suggestion for improving is welcome!

Have you put it to use / tested it in a "real world" setting?

Yes, why are you asking?

Because there are only two questions you have not answered and that was one of them. The other is a detailed list of parts but you've already listed the major components. In other words...

Around 500 views and no comment?

...the only comment anyone would have is "good job". So, good job!

(While "Yes, why are you asking?" does answer my question I am curious to know the details. For example: How sensitive is it? Does it trigger at 100% humidity? Or does liquid water have to be present?)

:slight_smile: Thank you!

Its in fact an Ohmmeter working best around 20MOhm, so you can change the threshold by calculating the ADC value for the desired resistances (For getting water alarm, <0,5MOhm would be good I think)

The threshold I used is quite sensitive, in the walls of a humid room it showed (with an extended version showing the MegaOhms) quick <5MOhm (after showering, no air exchange).

When the air was exchanged and the room heated afterwards it went to around 20MOhm.
(Wintertime, dry cold air gets heated, gets even dryer, <60% RH)
Very dry Rooms have also walls with around 50MOhms, but it depends also on the material of the concrete.

The only component not listed, is the 100nF Capacitor at the MCU Voltage supply pins for stabilizing the ADC.

Also worth to mention:
The reading of the Ohmmeter is not very exact (+-20% off?), because of sleep disturbing the adc , the frequency of the toggling and normal measuring errors.
It should be possible to improve that.

Maplins used to sell a unit for 5 quid which does this, batt life of a year or so iirc.

Thank you for this Information.

Do you have a link or the name of the device?

Does someone else know a similiar device?