ATtiny85 Plants Care

Your plant will have the needed water for months. Humidity and time since last watering are indicated! Low price and only a few components!

EasyFull instructions provided12 hours803
ATtiny85 Plants Care

Things used in this project

Hardware components

Attiny85 module
SparkFun Soil Moisture Sensor (with Screw Terminals)
SparkFun Soil Moisture Sensor (with Screw Terminals)
Pololu Mini MOSFET Slide Switch with Reverse Voltage Protection, SV
8x2 monochrome LCD
12V 280L/H Water Pump
LCD 1602 Adapter I2C

Software apps and online services

Arduino IDE
Arduino IDE


Read more


Fritzing schematics

Attiny85 plant care bb pfatdcardy


Arduino code for Attiny-plant-care

Just upload it in Attiny85 amd run.
/* Sketch for ATtiny85. Based on the Digispark (Use Digispark Default 16.5 MHz), no port select.
 *  Compile, Upload and then coonect ATtiny85 to USB.
 * {ATtiny85 alone pins: 1=PB5, 2=PB3,ADC3, 3=PB4,ADC2, 4=GND, 5=PB0,MOSI,SDA, 6=PB1,MISO, 7=PB2,SCK,SCL, 8=VCC}
 * ATtiny Pin 5 = PB0 (P0 on ATTiny board) = SDA 
 * ATtiny Pin 7 = PB2 (P2 on ATTiny board) = SCK=SCL 
 * ATtiny PB1 = to SWITCH power of a POLOLU MOSFET: power the Pump (6-12V)
 * ATtiny PB3 = Humidity sensor output= analog read
 * ATtiny PB4 = Power for the sensor (pin: 20mA = sufficient) 
*   Uses 26 mA for CPU, Sensor + Mosfet on + Display
 *  Uses 20 mA for CPU + Display (between readings)
 *  Uses 8 mA in deep sleep (Display on only)
 * Between reads: deep sleep. Protection against over-watering by humidity sensor. 

#include <TinyWireM.h>                  // I2C Master lib for ATTinys which use USI
#include <LiquidCrystal_attiny.h>       // for LCD w/ GPIO MODIFIED for the ATtiny85
#define GPIO_ADDR 0x27                  // the address i2c for this 8x2 LCD
LiquidCrystal_I2C lcd(GPIO_ADDR, 8, 2); // set the I2C address & 8/16 chars / 2 lines
// Utility sleep macros
#include <avr/sleep.h>
#include <avr/wdt.h>                    //Needed to enable/disable watch dog timer
#define adc_disable() (ADCSRA &= ~(1<<ADEN)) // disable ADC (before power-off)
#define adc_enable()  (ADCSRA |=  (1<<ADEN)) // re-enable ADC

#define LED_BUILTIN PB5           // Change PB5 to PB1 only for testing delays
#define powsen PB4                // PB4 provides 4.1V to power the humidity sensor
#define sensor PB3                // Sensor data pin for analog read
#define pump PB1                  // Pin for LED & MOSFET feeding the Pump

// Reading humidity once in 30min...1hour is sufficient:
int D, H, nr=100;                 // Attiny85 will sleep nr*9 (sec.) (E.g. 200=>30min; 400=>1h))
unsigned long psec, corr=nr*300; // time counter since start or watering

//This runs each time the watch dog wakes us up from sleep
ISR(WDT_vect) {
  //Don't do anything. This is just here for wake up.

void setup() {
 lcd.init(); lcd.backlight();  lcd.clear();
 pinMode(powsen,OUTPUT);      // Power to the sensor by powsen PIN
 pinMode(sensor, INPUT);      // Sensor read value from sensor PIN
 pinMode(pump, OUTPUT);       // Pump control PIN
 set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // sleep mode is set here
 sleep_enable();                   // enables the sleep bit in the mcucr register, so sleep is possible
 psec=0;                              // Starting moment

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);      // turn the LED on (HIGH is the voltage level)     
  digitalWrite(powsen,HIGH);           // Power on the sensor 
  int humidity=analogRead(sensor);     // Read sensor data
  delay(200);                          // A short time, just to read the sensor!
  digitalWrite(powsen,LOW);            // Power off the humidity sensor
  digitalWrite(LED_BUILTIN, LOW);       // turn the LED off by making the voltage LOW
  // Convert analog values from sensor to humidity. Tested: free and short-circuit. 
  humidity = constrain(humidity, 85, 660);   // accept values between these limits for 4.8V on sensor 
  humidity = map(humidity, 85, 660, 0, 100); // and map them between 0 and 100%

  // The pump is started if humidity drops below a level determined for each plant!
  // Then, the pump cannot restart before 'pause', waiting for water to diffuse in the pot.
  // Set below the DRY Limit for Your Plant (E.G.: 95):
  if (humidity<=95) {                   
    digitalWrite(pump,HIGH);        // Power the pump through a Pololu-LV-MOSFET
    delay(15000);                   // Time [ms] to pump the tested REQUIRED volume of WATER to the plant!!
    digitalWrite(pump,LOW);         // Power down the pump through the MOSFET
    psec=0;                        // Reset timer of water pumping. 
    // Test that after [nr*9] seconds (15min in this case), water was absorbed and sensor is above threshold.
    // Otherwise, the pump will start again after. Warning: too much water can be bad for your plant!   

  // Show the results on the screen
  lcd.setCursor(0, 0);  lcd.print("Mimosa:");
  if (humidity>95)
    if (humidity>97)
  lcd.setCursor(0, 1);  
  lcd.print(humidity); lcd.print("%");      // Write on LCD the humidity (%) and
  D=psec/86400;                            //  days since last watering/reset ...
  H=(psec%86400)/3600;                     //    and hours
  lcd.print(D); lcd.print("d");
  lcd.print(H); lcd.print("h ");
  // Most of the time, go to sleep for 'nr' multiples of 8 seconds + opp. time         
  adc_disable(); // ADC uses ~320uA
  for (int i=0; i<nr; i++){
    setup_watchdog(9); //Setup watchdog to go off after 9->8s sec + opp. time
    sleep_mode(); //Go to sleep! Wake up n sec later and work
  delay(corr);                    // Timer correction since sleep is less than nr*9 sec.
  psec+=nr*9;                      // Update timer after deep sleep for Half an hour

// ===================================================================
void setup_watchdog(int timerPrescaler) {
    //Sets the watchdog timer to wake up, but not reset
    //0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms
    //6=1sec, 7=2sec, 8=4sec, 9=8sec
    //From: http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
  if (timerPrescaler > 9 ) timerPrescaler = 9; //Limit incoming amount to legal settings
  byte bb = timerPrescaler & 7; 
  if (timerPrescaler > 7) bb |= (1<<5); //Set the special 5th bit if necessary
  //This order of commands is important and cannot be combined
  MCUSR &= ~(1<<WDRF);            //Clear the watchdog reset
  WDTCR |= (1<<WDCE) | (1<<WDE);  //Set WD_change enable, set WD enable
  WDTCR = bb;                     //Set new watchdog timeout value
  WDTCR |= _BV(WDIE);  //Set the interrupt enable, will keep unit from resetting after each int




3 projects • 3 followers
Arduino projects are a hobby for me.