I have been researching and learning about Serverless Architectures since May 2016. Until recently I had been working on small projects. These projects focused on learning about different Serverless frameworks and deploying Serverless projects. These were good learning experiences for me. Yet, small projects do not explore many of the benefits of Serverless Architectures. It was time for me to look at making something larger.
While I love gardening, I often forget to water my plants. My garden is on my balcony and only receives water when I water the plants. If I fail to water my plants, the plants wilt and die. To prevent this, I wanted a system that would inform me when my plants need watering.
There are two key halves to this problem. The first half is soil moisture sensing and data ingestion. I need a device in my plants that will measure soil moisture and send it somewhere for processing. The other half is the user facing monitoring and notifications. I need an alert sent to me when the moisture drops below a particular level.
I chose to build this as a Serverless system to increase my knowledge and for fun. But, there are other reasons why a Serverless Architecture is a good choice for this system. To explain why it is a good choice, I want to attempt to define Serverless Architectures.
A Serverless Architecture is an event driven system that utilises FaaS and other fully managed services for logic and persistence.
Serverless Architectures are different to systems built on PaaS services as they are event driven and have a different unit of scale.
An event driven system is a natural fit for the problem I am attempting to solve. Soil measurement events are generated by the device every 15 minutes. Notifications are only sent in response to a low moisture level event. Requests for monitoring data by users will be volatile and unpredictable. A Serverless Architecture allows me to worry less about listening to events and focus on responding to events.
Slack notifications for low moisture levels
To solve this problem I created a system with the architecture as below.
The AWS IoT Service provides a secure way to connect devices to AWS. Devices can publish events to the IoT Hub for processing by the IoT Rules Engine. The rules engine can store data in DynamoDB, invoke Lambda functions and more.
The AWS IoT service is the boundary between the sensors and the users. The IoT rules respond to sensor events and perform actions which form the inputs of the user systems. In this case that is storing the soil moisture levels DynamoDb and invoking a Lambda function in the notification system.
The monitoring system is a Web based dashboard. The client is a React based Single Page Application (SPA) hosted on Firebase. The backend is a GraphQL endpoint built with API Gateway, Lambda and DynamoDb. Auth0 provides for authentication for the dashboard. Users login through the client and pass a token to the backend.
The notifications system sends messages to a Slack channel. The IoT hub invokes a Lambda function for each sensor data event. The Lambda function decides whether or not to send a notification. To notify the client, the decider publishes a message on a SNS topic. The SNS topic invokes another Lambda function which sends a message to Slack.
There are alternative ways to design this system. But this design keeps each Lambda focused on one task. It also makes it easy to add other notifications in the future, Text message, Email, ect.
Over the coming weeks I plan on writing about how I implemented each component. The project is far from perfect, but many of the components are already implemented. If you want a sneak peek at the code you can find it on Github. To learn about more about GraphQL and the Serverless Framework try this video course that covers both in-depth.