In-House.Greenhouse.mp4
- 1. Problem description
- 2. Our solution
- 3. System architecture
- 4. Infrastructure
- 5. Circuit Diagram
- 6. Development
- 7. 3D renderings
- 8. Working prototype
- 9. Directory structures
- 10. Links to project resources
- 11. Partners and sponsors
The use of agricultural fields is fundamental for the production of primary goods necessary for human beings, but this involves numerous carbon emissions used in the transport of the goods to department stores or shops. These carbon emissions are then released into the air in the form of greenhouse gases through transportation. Like many other human activities, these emissions contribute to global warming.
In-House Greenhouse lets you control your smart greenhouse via your smartphone from anywhere in the world. You'll never have to ask a friend to water your plants again! This smart greenhouse allows you to fully manage up to 6 plants, providing water and collecting valuable information, such as soil moisture and air temperature. The collected data is used to generate statistics on your plant's growth and to alert you in case of any issues with one or more plants in your in-house greenhouse. You can also share this data with friends, allowing you to compare statistics.
This diagram provides an overview of the components that constitute the In-House Greenhouse system. The greenhouse collects data regarding plant conditions and the surrounding environment through sensors. This data is then transmitted to the server using HTTP calls to the API, where it is stored in a PostgreSQL database.
The phone application relies heavily on the API for its functionality. Data displayed in various interfaces, including the list of added greenhouses and statistics for different plants, is fetched dynamically through HTTP requests sent to the API. Users, through the phone application, can not only view but also modify this data. They have the ability to edit information for any greenhouse and any plant owned by the user.
The heart of the application, the APIs, runs within a Docker container, including the database to which they are connected. Utilizing containers provides several advantages, notably the ability to scale up the number of API containers dynamically when the primary container experiences high load. Docker-Compose simplifies the process of launching the entire application on any platform, requiring no additional configuration.
This chapter describes each component present in the system, delving into the technologies and languages used for their development.
In-House Greenhouse IoT |
|
In-House Greenhouse App |
|
In-House Greenhouse Server |
|
In-House Greenhouse Database |
|
The application is developed with React Native and Expo using TypeScript. To simplify the development of the application views, the app uses Ui Kitten as the UI framework.
The software behind the physical IoT greenhouse allows it to be managed autonomously. Its software, which has been named "GreenCore," enables the greenhouse to autonomously handle both the configuration part (at the first power-up, a greenhouse must be registered within the system via API). It has been entirely implemented in Java, employing parallel programming techniques to optimize sensor reading processes. Furthermore, the Pi4J library (version 1.4, link) is used to control the GPIO pins of the Raspberry Pi 3 Model B+.
The greenhouse features the following sensors:
- 6 soil moisture sensors to collect soil data from plants
- 1 water level sensor that monitors the water tank level
- 1 air temperature sensor
- 1 air humidity sensor
The data generated by the sensors is made available through the smartphone application via special APIs that handle data storage within the database.
The API server is managed using the GraphQL query language. The use of this particular query language allows developers to request only the necessary data from the API, thus avoiding unnecessary network traffic and expensive queries. The API manages every aspect of the system; in fact, it's only through the API that data can be read and written to the database. The API server is the only component of the system that can connect directly to the database and query it.
For API communication, it's mandatory to use HTTP POST requests with the GraphQL query contained in the request body. For more information on creating these queries, you can consult the official guide: GraphQL Queries Guide.
The entire system was developed through Apollo Server (link), a suite that combines the well-known back-end framework ExpressJS with the fantastic query language GraphQL. To further facilitate database development, the Prisma ORM (link) is used. This framework allows you to describe the database structure in textual form (a so-called "schema") and, through an operation called "migration," transform it into SQL commands that are executed automatically inside the PostgreSQL server, applying schema changes automatically to the various tables.
The database is a simple PostgreSQL server and is managed autonomously through a Docker container (managed with docker-compose, Docker Compose Reference) using the following image: postgres:11.10. Through the configuration file related to docker-compose (docker-compose.yml), you can modify several essential parameters, such as the username and password, or the name of the database created by default at startup.
This is the circuit diagram of the physical system, illustrating how various components are interconnected:
For the full-size version of the circuit diagram, click here.
The database is implemented using PostgreSQL and is hosted on a Docker container. It is connected to the API using the Prisma ORM. Here's the database ER diagram:
Every table in the database is defined in the Prisma schema. You can find the schema definition in this file.
A notable feature of this database is that plant data is never completely deleted but is only hidden by setting the isDeleted flag to "true."
The API server serves as the core of In-House Greenhouse. As mentioned earlier, the server was developed using Apollo Server (a web server) with GraphQL (an API query language) and Nexus GraphQL (a schema generator). The API server utilizes the Prisma ORM database to handle queries and database modifications.
APIs are categorized into two primary groups:
-
Queries: This group includes APIs that retrieve data from the database without making any modifications.
-
Mutations: In this group, you'll find APIs that are responsible for modifying data, including operations like deletion, modification, and insertion.
Below is a diagram illustrating the structure of the GraphQL API:
For the development of various queries, the server provides a Sandbox for testing, accessible via the loopback address: http://localhost:4000.
You can adjust server settings via the .env
configuration file.
Here's a list of all available settings:
Name | Description |
---|---|
DATABASE_URL | URL required for the database connection. |
JWT_ACCESS_TOKEN_SECRET | Secret key needed for JWT access token encryption (valid for 30 minutes). |
JWT_REFRESH_TOKEN_SECRET | Secret key needed for JWT refresh token encryption (valid for 7 days). |
JWT_GREENHOUSE_TOKEN_SECRET | Secret key needed for JWT greenhouse token encryption (valid for 1 minute). |
API_SERVER_PORT | Port where the APIs are accessible. |
API_SERVER_URL | Host where the APIs are accessible. |
The API server employs three types of tokens for authentication:
-
Access token: Provides access to the API, with a validity of 30 minutes. This token grants access to all APIs.
-
Refresh token: Allows for the renewal of the access token, with a validity of 7 days. This token serves no other purpose and cannot be used to access APIs.
-
Greenhouse token: An access token used by the IoT greenhouse to record data, with a validity of 1 minute. This token can only be used in the API related to the IoT greenhouse, specifically the one for recording data in the system (Mutation:recordData) and the one for retrieving recorded sensor data (Query:getSensors).
Here's a simple diagram illustrating the authentication process between the API server and the IoT greenhouse/Smartphone application:
The application initially presents a login/registration screen, which allows you to access the system. This authentication process is strictly necessary since the user needs the access and refresh tokens to make calls to the API (see Chapter 6.2.3 Authentication).
Once logged in, the application shows the homepage, where you can view all the greenhouses managed by the user. When you select a greenhouse, the application shows a summary screen displaying all the plants in that greenhouse. This is a screenshot:
Plants can be added using the appropriate button at the top right (symbol "+") or modified by tapping on the "Edit Plant" button inside the plant card.
You can view the statistics of a specific plant by tapping on the "Health Status" button inside the plant card. If the plant has not yet received any data, the system will show a warning message; otherwise, it will display a summary of the statistics.
You can navigate the app via a drawer on the left, which can be opened either by swiping to the right or by clicking the hamburger icon on the homepage.
Note: In this chapter, I have shown only the most important screens, so there are no screenshots of every interface present.
GreenProxy is an application written in Go (https://go.dev), which allows you to manage the communication between Greenhouse IoT and the API server. The greenhouse, when it has to perform a request to the API, sends it to GreenProxy, which manages the authentication (request of the greenhouse token) and the communication with the API server (sends the GraphQL query to the API server and returns the response to the sender).
This is an example of GreenProxy's output, showing the startup process (where the config file is loaded) and the request forwarding process (with its authentication):
GreenProxy is used within a Docker container to run the application in isolation from the rest of the application. You can activate the proxy via the command docker-compose up
.
GreenCore is the software that manages the IoT greenhouse. The system has been programmed as a state machine, where, in order to proceed to the next state, the current state must be successfully terminated. Each state is called a "Sequence" and is defined by a class that extends the ISequence interface. The system uses three states:
- SplashScreen Sequence
In this sequence, a splash screen is printed on the terminal, showing the title of the application (GreenCore) and its authors.
- Setup Sequence
During the setup sequence, the greenhouse tries to detect if it has already been configured. If it has been configured, there is a configuration file that keeps the UUID of the device, the name, and its description if present. If it has already been configured, it proceeds to the next state (Startup Sequence). Otherwise, a WebSocket is opened, allowing the greenhouse to receive its configuration from the user. The configuration is sent in JSON format and must have this format:
{
"token": "<USER ACCESS TOKEN>",
"name": "<GREENHOUSE NAME>",
"description": "[OPTIONAL DESCRIPTION]"
}
Note: For security reasons, it is necessary to send an access token (the same one the user uses to make requests to the API from the app) to access the greenhouse creation API (Mutation:addGreenhouse).
If the data submitted by the user is valid, the greenhouse announces itself to the API server, sending its name and description. If the creation is successful, the API will send the greenhouse its UUID, which will be used to request the greenhouse token (see Chapter 5.2.3 Authentication). If, on the other hand, the configuration provided is invalid, the greenhouse will send the user an error message notifying them of the problem.
- Startup sequence
The startup sequence is the operational state of the greenhouse. During this sequence, the greenhouse dynamically loads sensors and their identifying names directly from the API (Query::getSensors). Next, it assigns each sensor to a separate thread, managed by the MonitoringOrchestrator class. This orchestrator manages the pool of threads, handling their startup and possible problems generated. If a thread breaks, the orchestrator will try to restart it automatically to avoid unwanted problems.
The monitoring settings are defined by a MonitoringConfig object, which provides the following fields:
Name | Usage |
---|---|
greenhouse |
Greenhouse object that represents the current greenhouse |
timeBetweenChecks |
Milliseconds between sensor readings |
The following render images show the design of the In-House Greenhouse:
Credits: Danny Nguyen, Penn State student
.
βββ in-house-greenhouse/
βββ greenhouse-app # Greenhouse App
βββ greenhouse-server # Greenhouse API server
βββ greenhouse-iot/ # Greenhouse IoT files
βββ GreenCore # GreenCore
βββ GreenProxy # GreenProxy
βββ UPnP # UPnP discovery (UNUSED)
greenhouse-app/
βββ app/
β βββ assets/ # App assets
β βββ components/ # React native components
β βββ config/ # Config file loader (DO NOT TOUCH!)
β βββ i18n/ # Multi-Language
β βββ models/ # MobX State Tree data models
β βββ navigators/ # App navigators (Stack, Drawer, Bottom Tab)
β βββ screens/ # App screens
β βββ services/
β β βββ api/
β β β βββ core/ # API library core
β β β βββ authentication/ # Authentication API service
β β β βββ data/ # Data API service
β β β βββ greenhouse/ # Greenhouse API service
β β β βββ plant/ # Plant API service
β β β βββ position/ # Position API service
β β βββ keychain/ # KeyChain credentails service
β β βββ reactotron/ # Reactotron service (DO NOT TOUCH!)
β βββ theme/
β βββ utils/
β βββ app.tsx
βββ e2e/ # Detox End-To-End Testing
βββ test/ # Boilerplate default tests
greenhouse-server/
βββ extra/
β βββ db/ # Database ER diagram
β βββ graphql/ # GraphQL API diagram
βββ prisma/
β βββ ...
β βββ schema.prisma # Prisma schema
β βββ seed.ts # Prisma database seeder
βββ src/
βββ api/ # GraphQL APIs
βββ utils/
β βββ env/
β β βββ env.ts # Environment loader utility class
β βββ jwt/
β β βββ jwt.ts # JWT token utility class
β βββ request/
β βββ authentication.ts # Requests utility class
βββ server.ts # !API server entry point!
The file structure for the Greenhouse IoT files is too extensive to be described here. You can find it in the repository by clicking here. In addition, here you can find the GreenCore JavaDoc.
Links to each of the following project resources:
This project was the result of collaboration with SUPSI (University of Applied Sciences of Southern Switzerland) and Penn State University. We express our gratitude for this opportunity.