Project tutorial
An Urban Garden Monitor

An Urban Garden Monitor © GPL3+

An innovative solution for remote monitoring of data and trends in an urban garden environment.

  • 1,998 views
  • 0 comments
  • 5 respects

Components and supplies

Wiz750sr ttl evb package 1024x858 1mcfig9l3s
WIZnet WIZ750SR-TTL-EVB Kit
Only the Serial to Ethernet module is used in the final product. The other equipment is used for testing and configuration of the board.
×1
Ardgen 101
Arduino 101 & Genuino 101
I used the Arduino 101, which is identical to the Genuino 101.
×1
Adafruit BMP180 Barometric Pressure/Temperature/Altitude Sensor- 5V ready
This module is retired; I used it because I had it available. The successor, the BMP280 unit, has a different API which will require some adaptation to use.
×1
10167 01
DHT22 Temperature Sensor
Compared to the DHT11, this unit offers greater temperature and humidity range, which is beneficial for the diverse climates around the world.
×1
Arduino Holder for Arduino
I used a clear transparent holder that came with another board. The Arduino 101 did not come with a holder, but you can obtain one from the above link. This holder is useful for protecting the board when in use.
×1
SparkFun Solid Core Jumper Wires, 22AWG
All the jumper wires you need can be found in this kit. See the circuit diagram for sizes and quantities.
×1
SparkFun Breadboard - Mini Modular (White)
×1
Adafruit industries ada62 image 75px
USB-A to B Cable
Make sure your cable is long enough to reach from your wall outlet to your application area. If not, consider also using a USB A extension cable.
×1
USB Wall Charger
These are the devices you plug into the wall to charge mobile devices. Any generic USB wall charger will work. I used a simple 5V 1A charger with a single USB A output.
×1
RJ45 Ethernet Cable
The direct type, not the crossover type. Make sure your cable can reach from your router to your device's application area.
×1
USB to RS232 DB9 Serial Adapter
If your computer does not have a DB9 port, you will need this component to test the WIZ750SR-TTL-EVB. Make sure that the DB9 end is able to plug into the serial cable included with the EVB kit.
×1
SparkFun Jumper Wires - Connected 6" (F/F, 20 pack)
I used four of these wires in the Urban Garden Monitor.
×1

Necessary tools and machines

Electrical Tape
Generic electrical tape used to secure everything together. A pair of scissors helps with this.

Apps and online services

Ide web
Arduino IDE
SocketTest - Test My Socket
Easy to use TCP Client/Server software used for communication with the WIZ750SR over Ethernet.
WIZnet-S2E-Tool-GUI
Configuration tool for the WIZ750SR.

About this project

This device allows for fast, secure and remote analysis of the environment around an urban garden. Powered by the WIZnet WIZ750SR Serial to Ethernet module in conjunction with an Arduino 101, the Urban Garden Monitor reads temperature, humidity & pressure data and uses an integrated neural network to classify them into a system of categories.

The device was created using a few intertwined ideas:

WIZnet WIZ750SR Serial to Ethernet Module

The WIZ750SR is a serial to Ethernet module that allows any device with a serial port to connect to the internet. The module uses the W7500P processor, which combines an ARM Cortex-M0 with 128KB flash and a hardwired TCP/IP core to allow seamless connections between serial and Ethernet data. In the Urban Garden Monitor, the WIZ750SR bridges the gap between the environment data gathered by the Arduino 101 and the TCP Client terminal accessible on any device connected to the same router as the WIZ750SR.

Arduino 101 and Pattern Matching Engine Neural Network

The Arduino 101 is a unique development board that opens up the capabilities of the Intel Curie module in the Arduino form factor. Featuring a real-time operating system, integrated BLE, a six-axis accelerometer/gyro module and a 128 node Pattern Matching Engine (PME), or artificial neural network. The Urban Garden Monitor makes use of the RTOS and the PME to provide optimized characterization of daily environment data into a 30 category bank that fills up as the device learns different categorizations of this data, allowing users to visualize data trends and adapt their gardens as necessary. The Arduino 101 also comes with an additional hardware serial port, which is crucial to the operation of the WIZ750SR and functions as the link between the two devices.

BMP180 and DHT22 Environment Sensors

Featured on the Urban Garden Monitor are two environment sensors, the BMP180 and DHT22, used for collection of data to be interpreted by the Arduino 101 and PME. The BMP180 is a barometric pressure and temperature sensor that uses the I2C bus to communicate with devices, while the DHT22 is a temperature and humidity sensor that uses a single digital pin to communicate with devices. Together, these sensors provide an array of information that the Arduino 101 can interpret and send to the user.

How to Build

To build this device, first obtain all the components in the included bill of materials. Make note that your computer must have an Ethernet port. If you do not have a DB9 RS-232 port on your computer, obtain a USB to RS-232 DB9 adapter cable.

1. Configure the WIZ750SR. When you purchase the module as part of the EVB kit, the module will come attached to the evaluation board.

  • Plug the included DB9 RS-232 cable into the DB9 port of the EVB.
  • Plug the included USB Micro to USB A cable into the Micro-USB port of the EVB.
  • Plug the included Ethernet cable into the Ethernet port of the WIZ750SR on the EVB.
  • If necessary, plug the DB9 end of a USB to RS-232 DB9 adapter cable into your DB9 RS-232 cable and plug the USB end into your computer. Otherwise, plug the DB9 end of your DB9 RS-232 cable into your computer directly. You may need to download a USB to serial driver for your cable if it does not already exist in your computer.
  • Plug the USB A end of your USB Micro to USB A cable into your computer.
  • Plug the Ethernet cable into your computer. This will allow testing of device functionality.
  • Flick the power switch on the side of your board. LEDs will indicate that your device is powered up.
  • Make sure operation mode is set to "TCP Server." If necessary, use the upload button to update the device.
  • Unplug the Ethernet cable from the EVB and plug in your own Ethernet cable between your home router and the board. This will allow testing of device connectivity. Reopen the S2E-Tool software and check the "Local IP" and "Local Port" of your device. Once you have these, your device is ready to go.

2. Test the transmission of data through the WIZ750SR. Keep the device plugged in.

  • Download the latest version of the Arduino IDE from arduino.cc under Software->Downloads.
  • Open the Arduino IDE. Go to Tools->Port and select the communications port of your EVB. If there are multiple ports, check your computer's device list to see which one belongs to your board.
  • Go to Tools->Serial Monitor and open the monitor. Change the baud rate to 115200 baud.
  • Open SocketTest and go to the client tab. Type your EVB's IP address and port number into their respective fields. Hit connect to launch the terminal.
  • If everything was set up correctly, you should be able to type strings in the Arduino terminal and see them appear in the SocketTest terminal, as well as vice-versa. Once you're done testing the module, close all applications and unplug the EVB's cables.

3. Build the Urban Garden Monitor using the parts included in the bill of materials.

  • Unplug the WIZ750SR from the EVB. Flip the WIZ750SR so the headers face up.
  • Follow this circuit diagram to put together the electronics of the Monitor. Place electrical tape around the breadboard after wiring it before putting it in the center of the Arduino 101. Wrap the tape tightly to ensure stable connections, but make sure that the hole in the silver BMP180 unit is left exposed and facing up.
  • Note that the WIZ750SR header is composed of male pins. Use 4 F/F jumpers with a solid core M/M jumper on one end of each to create a low-profile connection on the Arduino 101.
  • Place the WIZ750SR on top of the mini breadboard and tape everything together. Tuck any loose jumpers to the side pockets of the Arduino 101. Make sure that the three LEDs on the WIZ750SR are still visible, and that the reset buttons along with the Ethernet and USB ports are accessible.
  • Attach the Arduino 101 to an Arduino holder to ensure protection of the board.

4. Upload the Urban Garden Monitor code to the Arduino 101.

  • Download the included code to your computer and open it in the Arduino IDE. Helpful comments are included in the file to guide you through understanding.
  • Go to Tools->Board->Boards Manager and find the Intel Curie Boards core. Download version 2.0.2.
  • Close the IDE.
  • Download the following additional code libraries to your computer:

Intel Pattern Matching Technology: https://github.com/intel/Intel-Pattern-Matching-Technology

Adafruit DHT Humidity & Temperature Unified Sensor Library: https://github.com/adafruit/DHT-sensor-library

Adafruit Unified BMP085/BMP180 Driver: https://github.com/adafruit/Adafruit_BMP085_Unified

  • Open your computer's filesystem and find the "Arduino" folder. Create a folder named "libraries" within it if it does not already exist. Open the folder and paste the three downloaded code libraries into the folder.
  • Reopen the Arduino IDE and plug the Urban Garden Monitor's USB port to your computer using a USB A-B cable. Go to Tools->Port and select the port of your Arduino 101. Then go to Tools->Board and scroll down to Intel Curie (32-bit) Boards. Select Arduino/Genuino 101.
  • Hit the upload button to upload the code to your board. You're ready to go!

Device Setup

To run the device, first set the Urban Garden Monitor up in the area where you would like to get environment readings. The best place for this would be close by to, if not beside a particular group of plants you may be concerned about, as this will allow you to get the most accurate readings for the plants you want to monitor.

Once you have positioned the Monitor, take a USB wall charger and plug a USB A-B cable into it. Plug the charger into a wall outlet. Take the B end of your cable and route it to where your Monitor is located. After this is ready, take your Ethernet cable from your router and route it to the Monitor as well. Plug the USB cable into the USB-B port and plug the Ethernet cable into the Ethernet port. You should first see a red LED light up, followed by a blue LED once the device has connected to the internet.

After your Monitor has been wired up, you can leave it alone. Go to your computer and open the SocketTest application. Type in the IP address and port number that you recorded earlier for the EVB and hit connect. Please note that the IP address may change if you add or disconnect any other devices between when you first get the IP address and now. If this is the case, you can check your router's homepage to see your Monitor's current IP address.

If the Monitor fails to connect, try again as it may take some time to be fully on the network.

Device Operation and Commands

Once you are connected, you should come to this screen:

Type in anything and hit send or the Enter key to activate the Monitor. You should then be prompted to give the current time. Type in the hours first, send, and then type in the minutes and send that. If you make a mistake, you can hit the Reset button on the Monitor and try again.

Once the time has been configured, you should reach a menu prompt. Here are the commands you can enter:

  • LD: This command creates a 2 second interval loop of sensor data readings using an Interrupt Service Routine. During this time, the loop will take priority over all other commands, so make sure not to activate any of the other data display commands during this time or they will be interrupted. This command is recommended for when you want to be able to remotely see the environment in which your plants are growing, so you can respond accordingly when conditions change.
  • DL: This command turns off the ISR data loop.
  • DD: This command sends a single snapshot of current sensor data readings.
  • SS: This command shows the previous day's average data and neural network categorization. If you call this command when no previous day data exists, you will be notified and no data will be shown.
  • ST: This command shows data categorizations of the past 30 days. Before a day is categorized, it will show up as category 0. Please note that category 0 will also be used by the first categorization that the device makes. You can modify this if you'd like by starting the array index at 1 and making it end at 30 instead of 29.
  • DC: This command displays what each saved numerical day data categorization represents. If the category has not been assigned characteristics, the data will show up as zero for all fields.
  • SC: This command shows the command list if you need it for reference.

PME Operation

During the operation of this board by the user, the Pattern-Matching Engine will run in the background. Each hour, the device will record a sample of the temperature, air pressure and humidity around the device. This data is then saved to the device in an array. After 24 recorded hours, the device takes an average of each dataset and creates a three variable representation of the environment of those past 24 hours. This data is then loaded into the PME, which categorizes it based off of learning experiences. If there is no prior categorization for which the PME finds a match, the data is given a new categorization and is saved to the PME's memory. Otherwise, an existing categorization is assigned. In both cases, the day's assigned categorization is then saved as well. The categorizations are put into a 30 day array which dynamically adapts to prevent overflow, deleting the oldest saved day and shifting all other data up, allowing the newest categorization to be recorded. This allows the user to see how the environment changes on a daily bases, allowing them to adjust their gardens to adapt to potential increasing or decreasing trends in data.

If the amount of categorizations exceeds 30, the oldest categorization is removed thereafter as the amount of storage space in the PME is limited.

Video

This video shows the operation of the Urban Garden Monitor and how to use the command interface.

Demonstration video for the Urban Garden Monitor.

Hopefully this project will allow people to have more time available for them in their lives and allow them to provide more benefit towards an urban garden that they may take care of!

Code

An Urban Garden Monitor ProgramArduino
This code runs the Urban Garden Monitor. Make sure to upload it to your device after you have installed all additional libraries as well as the Intel Curie boards core.
/*
   This is a sketch for the Urban Garden Monitor.

   It employs the Arduino 101 to collect temperature, pressue & humidity variables, and sends them using a WIZ750SR over Ethernet to a TCP Client terminal where data can be read.

   The onboard Pattern Matching Engine classifies daily averages of the data into a 30-category bank, creating an archive of data trends that can be interpreted by the user.

   It also saves all categorizations of the past 30 days for visualization of trends by the user.

   Make sure that you have the Adafruit sensor libraries and the CuriePME library installed.
*/

// Sensor libraries called in the code:

#include <Adafruit_Sensor.h> // Support library for the sensors.

// DHT sensor library, works with DHT11 or DHT22.
#include <DHT.h>
#include <DHT_U.h>

// This function declares an instance of the DHT sensor by stating the sensor readings pin, in this case pin 12, as well as the sensor type.
DHT_Unified dht(12, DHT22);
// I2C communication library.
#include <Wire.h>
// BMP085 Library, which also works with the BMP180 used in the device.
#include <Adafruit_BMP085_U.h>
// This function declares an instance of the BMP180.
Adafruit_BMP085_Unified BMP180 = Adafruit_BMP085_Unified(18001);

// Arduino 101 specific libraries:
#include <CurieTime.h> // Real-time clock.
#include <CuriePME.h> // Pattern-matching engine library.
#include <CurieTimerOne.h> // Timer functions library.

void setup() {
  // The code in setup() prepares all the components of the device and allows the user to set the current time.

  String time1, time2;
  // Initialize sensors, the PME and the serial port.
  BMP180.begin();
  dht.begin();
  CuriePME.begin();
  Serial1.begin(115200);
  while (!Serial1);
  // Do nothing while waiting for serial input.
  while (Serial1.available() == 0)
  {

  }
  // Read the input to clear the serial buffer but do nothing with the data.
  Serial1.readString();
  Serial1.println("UGM V.1.0.0 RELEASE");
  Serial1.println("By James Yu");
  Serial1.println();
  Serial1.print("Enter the current 24h time (hours): ");
  while (Serial1.available() == 0)
  {

  }
  // Wait for data to be typed in and save the data when it is.
  time1 = Serial1.readString();
  Serial1.println(time1);
  Serial1.print("Enter the current 24h time (minutes): ");
  while (Serial1.available() == 0)
  {

  }
  // Wait for data and save it.
  time2 = Serial1.readString();
  Serial1.println(time2);
  Serial1.println(time1 + ":" + time2);

  // This function sets the Arduino 101 RTC to the speficied times. As only hours and minutes are relevant, everything else is pre-defined.
  setTime(time1.toInt(), time2.toInt(), 00, 01, 01, 2018);
  Serial1.println();
  Serial1.println("LIST OF COMMANDS");
  Serial1.println("     LD Loop sensor data every 2 seconds.");
  Serial1.println("     DL Disable sensor data loop.");
  Serial1.println("     DD Display sensor data.");
  Serial1.println("     SS Show statistics of previous day's data readings.");
  Serial1.println("     ST Show trends of data in the past 30 days.");
  Serial1.println("     DC Display characteristics save data.");
  Serial1.println("     SC Show command list.");
}

// Boolean variables that tell whether a sensor is actually active or not.
boolean humidityStatus, temperatureStatus, bmpStatus;
// Numerical data variables.
float humidityValue, temperatureValue, bmpTempValue, pressureValue, temperature;

float data[24][3]; // Array for hourly data.
float vectorF[3]; // Array for averages of hourly data.
uint8_t vector[4]; // Array for averages to be classified into the PME.
float characteristics[30][3]; // Array for PME classifications and associated data.
int dayData[30]; // Array for classifications of the past 30 days.

int i;
int j = 0;
int category = 0;
int prevDayResponse = -1;

void loop() {
  // The code in the first section of loop() interprets serial commands.

  // If serial data is available during the loop, read it.
  if (Serial1.available() > 0)
  {
    String commandX = Serial1.readString();
    // Having "\r\n" at the end of each string check is necessary for the Arduino 101 to interpret sent strings properly.
    if (commandX == "LD\r\n")
    {
      CurieTimerOne.start(2000000, &dataLoopISR); // Activates an interrupt service routine every 2 seconds, which is set alongside any other code running.
    }
    else if (commandX == "DL\r\n")
    {
      CurieTimerOne.kill(); // Disables the interrupt service routine.
    }
    else if (commandX == "DD\r\n")
    {
      // This function prints out a single instance of sensor readings at the time the command is sent.
      Serial1.print("Time:");
      Serial1print(hour());
      Serial1.print(":");
      Serial1print(minute());
      Serial1.println();
      // If both the BMP180 and DHT22 are available, use the average of the two temperature values as the recorded temperature value.
      if (bmpStatus == true && temperatureStatus == true)
      {
        temperature = (bmpTempValue + temperatureValue) / 2;
        Serial1.println("Temperature:" + String(temperature) + "*C"); // Prints temperature.
        Serial1.println("Pressure:" + String(pressureValue) + "hPa"); // Prints pressure.
      }
      // If only the BMP180 is available for temperature, use that.
      else if (bmpStatus == true && temperatureStatus == false)
      {
        temperature = bmpTempValue;
        Serial1.println("Temperature:" + String(temperature) + "*C");
        Serial1.println("Pressure:" + String(pressureValue) + "hPa");
      }
      // If only the DHT22 is available, use that.
      else if (temperatureStatus == true && bmpStatus == false)
      {
        temperature = temperatureStatus;
        Serial1.println("Temperature:" + String(temperature) + "*C");
      }
      // If the DHT22 is available, read humidity values.
      if (humidityStatus == true)
      {
        Serial1.println("Humidity:" + String(humidityValue) + "%"); // Prints humidity.
      }
    }
    else if (commandX == "SS\r\n")
    {
      // This command prints data averages and classification of the previous day's readings.
      if (prevDayResponse == -1)
      {
        // This will only be called if no data has been classified yet. After the first 24 hours of operation, this should not appear again.
        Serial1.println("No previous day data yet!");
      }
      else
      {
        // If data exists, print it out.
        Serial1.println("Yesterday's data recordings:");
        Serial1.println("     Recorded category: " + String(prevDayResponse));
        Serial1.println("     Category temperature: " + String(characteristics[prevDayResponse][0]) + "*C"); // Data of the previous day's categorization (out of the 30 possible categories).
        Serial1.println("     Category pressure: " + String(characteristics[prevDayResponse][1]) + "hPa");
        Serial1.println("     Category humidity: " + String(characteristics[prevDayResponse][2]) + "%");
        Serial1.println("     Actual temperature: " + String(vectorF[0]) + "*C"); // The previous day's actual data for comparison.
        Serial1.println("     Actual pressure: " + String(vectorF[1]) + "hPa");
        Serial1.println("     Actual humidity: " + String(vectorF[2]) + "%");
      }
    }
    else if (commandX == "ST\r\n")
    {
      // This command calls up all the elements of the categorizations of the past 30 days.
      Serial1.println("Environment data for the past 30 available days:");
      Serial1.println("");
      for (int s = 0; s < 30; s++) // Print the array's elements sequentially.
      {
        Serial1.println("     " + String(dayData[s]));
      }
    }
    else if (commandX == "DC\r\n")
    {
      // This command prints out all the data associated with each category saved in the PME. This is helpful when used with the previous command.
      Serial1.println("Listing all saved daydata characterizations:");
      for (int h = 0; h < 30; h++)
      {
        // For each of the 30 categories, print associated temperature, pressure and humidity variables.
        Serial1.println();
        Serial1.println("     Category: " + String(h));
        Serial1.println("     Temperature: " + String(characteristics[h][0]) + "*C");
        Serial1.println("     Pressure: " + String(characteristics[h][1]) + "hPa");
        Serial1.println("     Humidity: " + String(characteristics[h][2]) + "%");
      }
    }
    else if (commandX == "SC\r\n")
    {
      // This prints the commands list.
      Serial1.println("LIST OF COMMANDS");
      Serial1.println("     LD Loop sensor data every 2 seconds.");
      Serial1.println("     DL Disable sensor data loop.");
      Serial1.println("     DD Display sensor data.");
      Serial1.println("     SS Show statistics of previous day's data readings.");
      Serial1.println("     ST Show trends of data in the past 30 days.");
      Serial1.println("     DC Display characteristics save data.");
      Serial1.println("     SC Show command list.");
    }
  }

  // The code in this section of loop() runs continuously and polls the sensors for data.

  // Define a sensor reading event for the BMP180.
  sensors_event_t event;
  BMP180.getEvent(&event); // Obtain sensor readings.
  if (event.pressure) // If air pressure data is available, the BMP180 is active (true). Obtain pressure and temperature data.
  {
    bmpStatus = true;
    pressureValue = event.pressure;
    BMP180.getTemperature(&bmpTempValue);
  }
  else // If no data is available, set the BMP180's status to unavailable (false). This should only happen if the sensor is not wired properly.
  {
    bmpStatus = false;
  }

  // Define a sensor reading event for the DHT22.
  sensors_event_t event1;
  dht.temperature().getEvent(&event1); // Get readings.
  if (isnan(event1.temperature)) {
    // If there are no numerical readings from the sensor, set the device's status for this variable to unavailable (false).
    temperatureStatus = false;
  }
  else {
    // If data is available, set status to true and get temperature data.
    temperatureStatus = true;
    temperatureValue = event1.temperature;
  }
  dht.humidity().getEvent(&event1);
  if (isnan(event1.relative_humidity)) {
    // If there are no numerical readings from the sensor, set the device's status for this variable to unavailable (false).
    humidityStatus = false;
  }
  else {
    // If data is available, set status to true and get humidity data.
    humidityStatus = true;
    humidityValue = event1.relative_humidity;
  }

  // This section of loop() runs every hour. It loads the environment data polled when the function runs into an array to be interpreted later.

  if (minute() == 0 && second() < 8 && bmpStatus == true && temperatureStatus == true && humidityStatus == true)
    // This only runs if all sensors are active. It has a 7 second buffer to prevent being missed if another function is running at the same time.
  {
    Serial1.println("Recording data...");
    // Put data into the spots in the array dedicated to the current hour.
    data[hour()][0] = temperature;
    data[hour()][1] = pressureValue;
    data[hour()][2] = humidityValue;
    if (j < 24) // If 24 hours have not elapsed, increment the hour counter.
    {
      j++;
    }
    else
    {
      // If 24 hours have passed, take an average of the data and load it into the PME.
      for (int x = 0; x < 24; x++)
      {
        // Conglomerate the sums of each variable type into a single array spot.
        vectorF[0] += data[x][0];
        vectorF[1] += data[x][1];
        vectorF[2] += data[x][2];
      }
      // Divide each value by 24, giving the average of the day's data.
      vectorF[0] = vectorF[0] / 24;
      vectorF[1] = vectorF[1] / 24;
      vectorF[2] = vectorF[2] / 24;

      // Convert the data to 8-bit format to be used for day categorization and comparison by the PME.
      vector[0] = map(constrain((int)vectorF[0], -40, 40), -40, 40, 0, 80); // Handles temperature data.

      // As pressure data will not fit in an 8-bit variable, split it in half.
      vector[1] = (int)(vectorF[1] / 100); // Takes the first 2 digits by dividing the value by 100 and converting to an integer, removing all digits after the decimal point.
      vector[2] = (int)vectorF[1] - (((int)(vectorF[1] / 100)) * 100); // Takes the last 2 digits by subtracting the above value from the original value * 100 from the original value.

      vector[3] = constrain((int)vectorF[2], 0, 255); // Handles humidity data.
      // Attempt to classify the data into the PME and get a response.
      int response = CuriePME.classify(vector, 4);
      if (response == CuriePME.noMatch)
      {
        // If the PME cannot classify the data, create a new category and use the data to characterize it.
        Serial1.println("New characterization-saving to memory.");
        CuriePME.learn(vector, 4, category);
        characteristics[category][0] = vectorF[0];
        characteristics[category][1] = vectorF[1];
        characteristics[category][2] = vectorF[2];
        prevDayResponse = category; // Set the "previous day variable" category to this so it can be called upon by the check previous day's data function later.
        category++; // Increase the category count.
        if (category == 30)
        {
          // If the amount of categories has exceeded 30, reset the category at 0 and keep going. This will allow the PME to progress by deleting the oldest category's data so as to not run out of space.
          category = 0;
        }
      }
      else
      {
        // If the PME found a category that closely matches the data of the past 24 hours, state it.
        Serial1.println("Data of the past 24H is similar to days with the following characteristics:");
        Serial1.println("     Category: " + String(response));
        Serial1.println("     Temperature avg: " + String(characteristics[response][0]) + " *C");
        Serial1.println("     Pressure avg: " + String(characteristics[response][1]) + " hPa");
        Serial1.println("     Humidity avg: " + String(characteristics[response][2]) + " % ");
        Serial1.println();
        Serial1.println("The actual data of the past 24H:");
        Serial1.println("     Temperature avg: " + String(vectorF[0]) + " *C");
        Serial1.println("     Pressure avg: " + String(vectorF[1]) + " hPa");
        Serial1.println("     Humidity avg: " + String(vectorF[2]) + " % ");
        prevDayResponse = response;
      }
      for (int q = 29; q > 0; q--)
      {
        // This function handles the 30 day characterization component. To prevent this array from overloading, the program moves each component of the array forward one unit.
        // This causes the oldest data, hosted on the last spot, to be deleted.
        // This also opens up the first spot to accepting new data.
        dayData[q] = dayData[q - 1];
      }
      dayData[0] = prevDayResponse; // Save the day's categorization to the array.
    }
    delay(8000); // Wait 8 seconds to make sure this function doesn't accidentally run twice in the same hour.
    Serial1.println("Done.");
  }
  // End of loop code, return to the beginning of the loop.
}

// This function helps with printing the time. If either the hours or minutes variable is less than 10, it adds a zero in front to make it fit ##:## format.
void Serial1print(int number) {
  if (number >= 0 && number < 10)
    Serial1.print('0'); {
  }
  Serial1.print(number);
}

// This function is an interrupt service routine called by the program when the "loop data" command is activated. It prints the same data as the "display data" command but loops every 2 seconds.
void dataLoopISR()
{
  // See the display data command for info on the components of this function.
  Serial1.print("Time: ");
  Serial1print(hour());
  Serial1.print(":");
  Serial1print(minute());
  Serial1.println();
  if (bmpStatus == true && temperatureStatus == true)
  {
    temperature = (bmpTempValue + temperatureValue) / 2;
    Serial1.println("Temperature: " + String(temperature) + "*C");
    Serial1.println("Pressure: " + String(pressureValue) + "hPa");
  }
  else if (bmpStatus == true && temperatureStatus == false)
  {
    temperature = bmpTempValue;
    Serial1.println("Temperature: " + String(temperature) + "*C");
    Serial1.println("Pressure: " + String(pressureValue) + "hPa");
  }
  else if (temperatureStatus == true && bmpStatus == false)
  {
    temperature = temperatureStatus;
    Serial1.println("Temperature: " + String(temperature) + "*C");
  }
  if (humidityStatus == true)
  {
    Serial1.println("Humidity: " + String(humidityValue) + " % ");
  }
  // Once everything has been printed out, restart the ISR timer and set it to wait for 2 seconds before running this function again. This allows it to loop.
  CurieTimerOne.restart(2000000);
}

Schematics

An Urban Garden Monitor Circuit Schematic
Circuit diagrams for the Urban Garden Monitor. Please note the comments that will help you during the process of creating the device.
urban_garden_monitor_1AR39oD7UZ.fzz

Comments

Similar projects you might like

An Urban Plant Watering Solution

Project tutorial by James Yu

  • 17,325 views
  • 15 comments
  • 50 respects

Portable Environment Monitor

Project tutorial by Chathuranga Liyanage

  • 2,052 views
  • 1 comment
  • 6 respects

Eco-Thing #1 "Eco-Smart-Container V1.0"

Project tutorial by Alexis Santiago Allende

  • 5,305 views
  • 4 comments
  • 28 respects

Save Your Life with the Building Collapse Monitor

Project tutorial by Tharindu Suraj

  • 2,559 views
  • 2 comments
  • 23 respects

Smart Garden

Project showcase by patel Dipen

  • 22,323 views
  • 15 comments
  • 59 respects

Battery Charger Monitor

Project tutorial by David Kanceruk

  • 3,503 views
  • 1 comment
  • 18 respects
Add projectSign up / Login