element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
    About the element14 Community
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      •  Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Arduino Projects
  • Products
  • Arduino
  • Arduino Projects
  • More
  • Cancel
Arduino Projects
Blog SmarDen: Sustainable gardening via Dropbox
  • Blog
  • Documents
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Arduino Projects to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: rubroe
  • Date Created: 16 May 2015 3:30 PM Date Created
  • Views 858 views
  • Likes 4 likes
  • Comments 1 comment
  • solar-powered
  • gardening
  • iot applications
  • mbse
  • sysml
  • arduino
  • dropbox
Related
Recommended

SmarDen: Sustainable gardening via Dropbox

rubroe
rubroe
16 May 2015

In order to control plants via Dropbox we built the following control circuit / Cyber Physical System (CPS) / Internet of Things application. To support sustainability, the water used is taken out of a natural pond. The required energy is supplied by a solar panel that charges an old automotive accumulator (battery). Images of the plant growth progress and data is being sent to dropbox constantly. This project was part of a thesis and the advanced development / recursive modelling has been performed with SysML to verify applicability of Model Based Systems Engineering (MBSE) in the context of IoT and CPS.

 

{gallery} Layout

image

Layout:

image

Schema:

image

SysML CPS Profile & abstract reference architecture (1/3):

{gallery} Dropbox GUI and Hardware

image

Measured data: Battery level; Humidity; Temperature; XBee connection; Water level

image

Images sent to Dropbox:

image

Arduino:

image

Battery:

Arduino code:

#include <MemoryFree.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
#include <avr/power.h>


#include "pb_encode.h"
#include "pb_decode.h"
#include "messages_pb.h"


#include <SoilHumidity2.h>
#include <LM35.h>


//#include <AltSoftSerial.h>
#include <SoftwareSerial.h>


#include <JPEGCamera.h>


// sensors


SoilHumidity2 hsensor(3, 1); // soil resistance sensor: digital out pin, analog in pin
LM35 tsensor(0); // temperature sensor: analog in pin


const int batVPin = 2;   // bat level analog pin
const int waterVPin = 3; // water level in pin
const int waterOPin = 5; // water level sensor digital out pin
const int pumpOPin = 6;  // pump digital out pin


long pumpEndT = -1; // time to turn pump off, -1 if pump is off


long lastCommand = millis(); // time of last command. if we do not receive a command within 2 min. we go to sleep for 56 secs -> save power
int pumpBattLevel = 0;  // level of bat while pumping


const int WATER_LEVEL = 400;




// communication
SoftwareSerial s(8,9);      // cam serial
SoftwareSerial s2(10,11);  // xbee serial




JPEGCamera cam(s);




// xbee comm protocol
const unsigned int MAGIC = 7557; // frame prefix


messages_SensorData sensorData;
messages_Command commandData;
messages_picData picData;
messages_Ok okData;


char rBuffer[16];      // read buffer
uint8_t wBuffer[32];   // write buffer
pb_ostream_t stream;




// xbee comm protocol parsing
int readState = 0; // 0: magic_h, 1: magic_l, 2: len_h, 3: len_l, 4: buffer
int readExpectedLen = 0;
int m;
uint8_t h;
uint8_t l;


uint8_t command = 255;
int command_arg;


// control led
int led = 13;
int value = HIGH;


// power control
volatile long sleepOn = 0;
int powerPin = 12;


void softReset() // Restarts program from beginning but does not reset the peripherals and registers
{
  asm volatile ("  jmp 0");
}




ISR(WDT_vect)
{
  //Serial.println("ISR");
  if (sleepOn > -1)
  {
  }
  else
  {
    softReset();
  }
}




void setupWDT()
{
  /*** Setup the WDT ***/


  /* Clear the reset flag. */
  MCUSR &= ~(1<<WDRF);


  /* In order to change WDE or the prescaler, we need to
   * set WDCE (This will allow updates for 4 clock cycles).
   */
  WDTCSR |= (1<<WDCE) | (1<<WDE);


  /* set new watchdog timeout prescaler value */
  WDTCSR = 1<<WDP0 | 1<<WDP3; /* 8.0 seconds */


  /* Enable the WD interrupt (note no reset). */
  WDTCSR |= _BV(WDIE);
}


void enterSleep()
{
//   set_sleep_mode(SLEEP_MODE_PWR_SAVE);   /* EDIT: could also use SLEEP_MODE_PWR_DOWN for lowest power consumption. */
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   /* EDIT: could also use SLEEP_MODE_PWR_DOWN for lowest power consumption. */


  /* Now enter sleep mode. */
  sleep_enable();
  sleep_mode();






}


void camSave()
{
  /*
   s.begin(38400);
    s.listen();
  wdt_reset();
  cam.reset();
  delay(6000);
  wdt_reset();
  cam.powerSaving(true);
  */
}




void sleepIt(long duration)
{
  LEDLow();
  sleepOn = duration/8000;
  if (sleepOn == 0)
    sleepOn = 1;
  digitalWrite(powerPin, LOW);
  while (sleepOn)
  {
    enterSleep();
  /* The program will continue from here after the WDT timeout*/
    sleepOn--;
  }
  sleep_disable(); /* First thing to do is disable sleep. */

  /* Re-enable the peripherals. */
  power_all_enable();
  delay(100);
  digitalWrite(powerPin, HIGH);


// camSave();
}




// parse xbee comm
void doSerial()
{
  s2.listen();
  //Serial.println("event");
  while (s2.available())
  {
    invertLED();
    switch (readState)
    {
    case 0:
      h = s2.read();
      if (h == highByte(MAGIC))
        readState = 1;
      break;
    case 1:
      l = s2.read();
      m = word(h,l);
      if (m != MAGIC)
        readState = 0;
      else
      {
        readState = 2;
      }
      m = 0;
      break;
    case 2:
      h = s2.read();
      readState = 3;
      break;
    case 3:
      l = s2.read();
      readExpectedLen = word(h, l);
      // Serial.print("len ");
      //  Serial.println(readExpectedLen, DEC);
      if (readExpectedLen > 32)
      {
        readState = 0;
      }
      else
      {
        readState = 4;
      }
      break;
    case 4:
      if (s2.readBytes(rBuffer, readExpectedLen) == readExpectedLen)
      {
        pb_istream_t stream = pb_istream_from_buffer((uint8_t *)rBuffer, sizeof(rBuffer));
        pb_decode(&stream, messages_Command_fields, &commandData);
        command = commandData.command;
        //  Serial.print(7,DEC);
        //  Serial.println(command,DEC);
      }
      readState = 0;
      break;
    default:
      readState = 0;
      break;
    }
  }
}




void setup()
{
  stream = pb_ostream_from_buffer(wBuffer, sizeof(wBuffer));
  s2.begin(9600);    // set low xbee baudrate to reduce error rate.
  s.begin(38400);    // default cam baudrate is 38400
//  Serial.begin(9600);  // use serial for debug, but may block if used together with software serial
//  Serial.println("setup");
  pinMode(led, OUTPUT);
  pinMode(batVPin, INPUT);
  pinMode(waterVPin, INPUT);
  pinMode(waterOPin, OUTPUT);
  pinMode(pumpOPin, OUTPUT);
  pinMode(powerPin, OUTPUT);
  // turn xbee on
  digitalWrite(powerPin, HIGH);


setupWDT();
lastCommand = millis();


// camSave();

// set LED to high
LEDHigh();
   // wdt_enable(WDTO_8S);   // set watchdog to 8 seconds. may be set lower in future


}


void loop()
{
  wdt_reset();   // trigger watchdog
  if (pumpEndT > 0 && pumpEndT < millis())  // check if pump is on
    offPump();
  doSerial();  // parse input
  if (command < 255)  // if we received a command: execute it
  {
    lastCommand = millis();
    invertLED();
    wdt_reset();
    doCommand();
    command = 255;
    // Serial.print(0,DEC);
    // Serial.print(command, DEC);
  }
  else
  {
    if (pumpEndT <= 0 && (millis() - lastCommand) > 60000)
    {
      sleepIt(56000);
      lastCommand = millis()-55000;
    }
  }



}


void LEDHigh()
{
   value = LOW;
invertLED();
}


void LEDLow()
{
   value = HIGH;
invertLED();
}


void invertLED()
{
  if (value == HIGH)
    value = LOW;
  else
    value = HIGH;
  digitalWrite(led, value);
}


void doPump()
{


  pb_ostream_t stream = pb_ostream_from_buffer(wBuffer, sizeof(wBuffer));
  if (pb_encode(&stream, messages_Ok_fields, &okData))
  {
    //Serial.print("b ");
    //Serial.println(stream.bytes_written, DEC);
     sendMessage(stream.bytes_written);
  }
//     else
//  Serial.println("error encoding ok in doPump");


  long duration = commandData.arg;
// Serial.print(millis(), DEC);Serial.print(" doPump ");Serial.println(duration, DEC);
  if (duration > 0)  // duration 0 == heart beat
  {
    pumpEndT = millis()+duration;
    digitalWrite(pumpOPin, HIGH);
    delay(500);
    pumpBattLevel = getBatLevel(); // get bat level only when bat is under load
  }


}


void doSleep()
{
  long duration = commandData.arg;

  pb_encode(&stream, messages_Ok_fields, &okData);


  sendMessage(stream.bytes_written);


  if (duration > 0)  // duration 0 == heart beat
  {
    sleepIt(duration);
  }


}


int getBatLevel()
{
   return analogRead(batVPin);
}


void getWaterLevel()
{
  digitalWrite(waterOPin, HIGH);
  delay(500);
  int x = analogRead(waterVPin);
  digitalWrite(waterOPin, LOW);
  bool hasWater = x > WATER_LEVEL;
  sensorData.hasWater = hasWater;
}


void offPump()
{
  //  Serial.print(millis(), DEC);Serial.println(" offPump");
  pumpEndT = -1;
  digitalWrite(pumpOPin, LOW);
}


void sendPic()
{
  // Serial.println();
  // Serial.println(9, DEC);
  // Serial port connected to the cam
  s.listen();
  delay(1000);
  cam.reset();
  delay(4000);
  wdt_reset();
// cam.powerSaving(false);


  /*
  delay(50);
   cam.chBaudRate(1);
   delay(50);
   s.end();
   s.begin(19200);
   delay(50);
   */
  invertLED();
  cam.takePicture();
  wdt_reset();
  delay(25);
  picData.size = cam.getSize();
  pb_ostream_t stream = pb_ostream_from_buffer(wBuffer, sizeof(wBuffer));
  pb_encode(&stream, messages_picData_fields, &picData);


  sendMessage(stream.bytes_written);
  delay(10);
  invertLED();
  wdt_reset();
  cam.readData(s2);
  s2.flush();
  cam.stopPictures();
  invertLED();
cam.powerSaving(true);


}


void sendSensorData()
{
  wdt_reset();
  sensorData.temperature = tsensor.temperature();
  wdt_reset();
  sensorData.humidity = hsensor.humidity();
  wdt_reset();
  if (pumpBattLevel > 0)
  {
    sensorData.batLevel = pumpBattLevel;
    pumpBattLevel = 0;
  }
  else
    sensorData.batLevel = getBatLevel();

  getWaterLevel();


  pb_ostream_t stream = pb_ostream_from_buffer(wBuffer, sizeof(wBuffer));
  pb_encode(&stream, messages_SensorData_fields, &sensorData);


  sendMessage(stream.bytes_written);
}


void sendMessage(size_t len)
{
// Serial.print("send ");Serial.println(len, DEC);
  sendStartMessage(len);
  s2.write(wBuffer, len);
  s2.flush();
  delay(100);
  //Serial.println("endsend");
}


void sendStartMessage(size_t len)
{
  s2.write(highByte(MAGIC));
  s2.write(lowByte(MAGIC));
  s2.write(highByte(len));
  s2.write(lowByte(len));
}


void doCommand()
{
  // Serial.print(8,DEC);
  // Serial.println(command,DEC);
  switch (command)
  {
  case 0:
    sendSensorData();
    break;
  case 1:
   doPump();
    break;
  case 2:
    sendPic();
    break;
  case 3:
    doSleep();
    break;
  default:
    break;
  }


}











     

 

BoM:

Raspberry Pi B+
Arduino Pro Mini
XBee
Charge Controller
Solar Panel
12V Battery
Temp Sensor
Humidity Sensor
Water Pump
Water Level Sensor

 

LinkSprite JPEG Color - Infrared
 
 
Open Source Software Packages:
Yet Another Java Service Wrapper http://sourceforge.net/projects/yajsw/
Yet Another Cron4J http://sourceforge.net/projects/yacron4j/
vfs dropbox plugin http://sourceforge.net/projects/vfs-dbx/
 
If you have any questions, please dont hesitate to contact us.
 
Best regards,
Ruben Rösner
  • Sign in to reply

Top Comments

  • DAB
    DAB over 8 years ago +1
    Nice update. DAB
  • DAB
    DAB over 8 years ago

    Nice update.

     

    DAB

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2026 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube