In this short blog series, I introduced you to Project GreenThumb, a project that I created to automate and monitor the process of growing seedlings with hardware, software and the cloud. If you haven’t read the other posts in this series, I encourage you to do so.
Project GreenThumb Part 1 - Automating & Monitoring Seedling Growth With Microcontrollers & The Cloud
Project GreenThumb Part 3 - Consuming and Persisting the Sensor Data in the Cloud
Project GreenThumb Part 4 - Reporting Queries and WebSockets
In this post, we’ll wrap things up by looking at the front-end, how I automated the application build to deploy things to the cloud, how I added support for push notifications and finally we’ll look at the current progress of the project against the stated goals.
Micronaut clearly shines as a “data first” cloud-native microservice platform, but what you may not know is that it also includes support and integrations for server-side view rendering. To avoid blocking the Netty event loop, Micronaut handles server-side view rendering on the I/O thread pool. A number of view rendering engines are supported (Handlebars, Velocity, Freemarker, etc) but I chose Thymeleaf because of my slight familiarity with it over the other choices. To render a view, your controller must return a
ModelAndView object which contains the name of the view template to render and the object to use as the model.
The view can access any model variable with the familiar
There was no need to complicate the front-end. I just needed to present the data in a way that would give me a quick, full overview of the current sensor data and I feel like I accomplished that with a simplified, yet responsive layout.
home view connects to the WebSocket server endpoint that I previously established and updates a list of reading values in memory (limiting it to the 50 most recent readings) when a new message is received.
For reports, a single page outputs a number of various views of the aggregated sensor data. For example, I can see the average readings by hour of day for the current day which lets me make necessary adjustments if things look out of the ordinary.
I can also gauge the long-term success of the project by seeing the averages by hour of day for all time.
Or by looking at the daily average by day:
Of course, since I have different goals for “day” vs. “night”, I need a report that shows the progress against those metrics:
And finally, an overall total average for the sensor data.
Of course, no project would be complete without automating the build process. For that, I added a GitHub Actions workflow. The workflow checks out the code, then builds the JAR file:
Then logs in to the Oracle Cloud Infrastructure Registry builds a Docker image (using the out-of-the-box
Dockerfile provided by Micronaut) and pushes the Docker image to OCIR.
Finally, I log in to my VM, stop the existing Docker image, and pull and run the latest image on the VM:
What good is collecting a bunch of data if there is no automated call to action when the data indicates it is necessary? I could have easily added some automated watering to the project, but since I’m new to growing things like this, I wanted to maintain some granulated (manual) control over that process until I was more comfortable with it. I figured it would be super handy to add push notifications using Pushover so that I would get a notification when the soil moisture indicated that I should take a look at things and water the seedlings. To integrate with my Pushover account I could have dropped in the
pushover4j library (side note: enough with the “4j” projects already!) but since it’s just a
POST request to the API, I decided to avoid adding another dependency and just use a declarative http client with Micronaut. First, I set up my Pushover config.
Next, I created a POJO to contain the API response:
Finally, I created the client interface. Micronaut will handle all the necessary plumbing at compile-time and the client is ready to use in the application.
Then I injected the client into my MQTT consumer, checked the readings when a message is received, and send a push notification (throttled to once every 20 minutes) if the soil moisture level dropped below 50%. Of course, this could be extended to other metrics and thresholds as necessary just by modifying the message argument as appropriate.
Here’s what the notification looks like on my Pixel3 XL device.
When I click on the notification I get a link to follow directly to the dashboard.
As of publishing, it’s been 3 weeks since the seedlings were planted. There have been some minor adjustments to both hardware and software as I learn what works best for the system, but so far the results are mostly in range (or certainly extremely close to the targets).
If we look at it from an “overall” standpoint (disregarding night/day or daily/hourly breakdown):
Data, however, only tells half the story. The results that really matter are whether or not the seedlings have sprouted and are looking healthy. To that end:
This story doesn’t conclude today and when it does conclude later on this year it will be much more difficult to quantify the achievement. You see, to me the success of this project relies on the flavor and heat of the hot sauce that it will ultimately result in, and flavor is truly subjective and depends on the tastes of the person who is judging the product. But I guess there’s another way to gauge the success of this project and that is to look at the value of the experience itself. In that light, I feel like the project has already been a huge success because it gave me something to plan, build, learn from, and share with the developer communities that I work with every day.
If you'd like to check out any of the code used in this blog series, please refer to the appropriate repos on GitHub:
I've written many blog posts about connecting to an Autonomous DB instance in the past. Best practices evolve as tools, services, and frameworks become...
Email delivery is a critical function of most web applications in the world today. I've managed an email server in the past - and trust me - it's not fun...
In my last post, we looked at the technical aspects of my Brain to the Cloud project including much of the code that was used to collect and analyze the...