Implementation Guide for pouring Tea via an API
This is a follow-up article on the “Improving Quality of Life: A Tea Pouring Solution for Anton”. This project is a collaboration between Anton and myself. Special thanks also goes out to Arseny Starostin, who supported the setting up process, settings up CI and reviewing PRs. The scope of the project is to leverage a microcontroller and a pump to pour tea. This pouring is done via an API endpoint. This article follows up on the requirements that have been set and the shopping list that has been defined, and highlights the hardware and software implementation.
Wiring up the Hardware
Software is little without the hardware to run it on. For this reason we start with the schema of the solution. The components include:
- Arduino R4 Wifi microcontroller
- A Motor Hat that is connected to the pump and the Arduino
- A DC jack that accepts 12 Volts barrel-jack PSU
- Tea Pump, that runs on 12 Volts
- On/Off Switch with LED
In the schematic, we can see how the power comes in via the barrel jack. The switch and LED belong together as a component, and the LED switches on when the power is being switched on, too. The Arduino Motor Hat accepts the 12 Volts and can modulate this current and provide it for Channels A and B. Channel A is being used to control the pump. In the current implementation we use the modulation merely as a switch, meaning that we provide the current, or we don't, but do not modulate it further with PWM.
Writing the Software
The software has been implemented using Platform.IO. This is a VS Code extension that has many quality of life features for developing with Embedded Devices. One of the foremost features is the project and package management, in which the entire project and all it files are managed and packages can be added and are managed within the project. Features like building, uploading, monitoring and testing the code further enhance the developer experience. So let’s take a look at the different components of the controller firmware. The controller can do three things:
- connect to WiFi
- accept HTTP GET requests
- pour tea (duh)
Quickstart
- The first thing you’ll do with the controller is connect it to your network. For that, modify the
secrets.h
accordingly. For the expected format, refer tosecrets.h.example
. - Once you flash the controller firmware to the arduino module, it will connect to WiFi, create a route for your HTTP requests, and print out information about the connection.
- Let’s take a closer look at the individual pieces. When connecting to WiFi, we will show the SSID, signal strength and the IP address where you can send requests to.
- We set up one route,
/pour_tea
that has one query parameter,milliseconds
, that regulates how long the pump will run. The process will validate that the query parameter is of the expected format (an integer bigger than zero).
Where to find what
All the code can be found in the repository. Just remember, RTFM!
In the Arduino project, the RemoteControl
module, found in the lib/Arduino
directory, is responsible for managing WiFi connections. It handles the display of network information and incorporates a mechanism for automatic reconnection.
Similarly, the WaterPumpController
module, also located in lib/Arduino/
, provides direct control over the water pump. Users can initiate both start and stop actions through this component.
Within the CommandProcessor
module, situated in the lib/
directory, various tasks are performed. It ensures the validation of input to the HTTP endpoint, retrieves the current status of the water pump, and facilitates the pouring of tea. This pouring action is achieved by invoking both the water pump and checking its status concurrently.
The main.cpp
file, residing in the src/
directory, serves as a central orchestrator. It establishes the route for handling HTTP requests and configures the overall application setup. Specifically, when a request is received, it triggers the pour_tea
function, initiating the process defined in the CommandProcessor
module.
Testing Software
Next, we’ll explore how to effectively unit test the Water Pump Scheduler System using Google Test, a popular C++ testing framework. We used the PlatformIO Native environment (check platformio.ini
for the exact configuration) to be able to run the test locally, without requiring the embedded device. Then tests can easily be triggered within the PlatformIO ecosystem and are also part of the CI, as implemented in the Repository.
Note that not all testing frameworks are compatible with the Arduino, meaning that if you want to run unit-tests on specific hardware, you need to assure compatibility of that framework beforehand. Our focus will be on two sets of tests: WaterPumpScheduler_test.h
and CommandProcessor_test.h
. We'll also discuss the use of mock classes like FakeWaterPump
and FakeWaterPumpSchedulerAPI
for simulating real components.
Testing the Water Pump Scheduler (WaterPumpScheduler_test.h
)
Test 1: Pump Stops After Given Time
- Objective: Ensure the water pump stops after a specified duration.
- Step 1: Setup a
WaterPumpScheduler
with aFakeWaterPump
. - Step 2: Start the pump and confirm it’s running and the stop time is correctly set.
- Step 3: Simulate time passing and check if the pump stops as expected.
Test 2: Periodic Forced Stop of Pump
- Objective: Verify the pump is forced to stop periodically.
- Step 1: Setup with a
FakeWaterPump
and a forced stop interval. - Step 2: Start the pump and validate it stops after 1 millisecond.
- Step 3: Simulate repeated starts and time passage, ensuring the pump stops each time.
Testing the Command Processor (CommandProcessor_test.h
)
Test 1: Pour Tea with Invalid Milliseconds
- Objective: Check the
pour_tea
method for errors with invalid inputs. - Step 1: Test various invalid inputs like too high numbers, negative numbers, empty strings, and non-numeric strings.
Test 2: Pour Tea Operation
- Objective: Ensure tea pouring starts and stops correctly.
- Step 1: Use
FakeEnvironment
andFakeWaterPumpSchedulerAPI
to simulate operations.
Test 3: Stop Method
- Objective: Confirm the
stop
method halts tea pouring. - Step 1: Use mock classes to test the stopping functionality.
Test 4: Status Method
- Objective: Verify the
status
method returns correct pump status. - Step 1: Check both idle and running states of the pump for accurate status reporting.
Mock Implementations for Testing
FakeWaterPump
Simulates a real water pump. It implements start
and stop
methods to change its running state and is useful for testing scenarios involving pump operations without needing a physical pump.
FakeWaterPumpSchedulerAPI
Mimics the behavior of a real water pump scheduler. It implements methods to start and stop the pump, including logging calls for verification. The status
method provides the current state of the pump, aiding in testing the scheduler's functionality.
Next Steps
The implementation of a reasonable workflow for managing the pouring of tea has been achieved. The use of a scheduler enables to manage the state of the device at all times, and the suite of tests ensures that the code itself can be validated and code-changes can be better understood. The next step is to package these functionalities and electronic hardware into something that we can put on a desk somewhere. The design should be simple and accessible. Apart from an intuitive design, we will also consider the cost and efficiency of 3D printing for this use-case.
Resources
- GitHub Repository that tracks the entire project: https://github.com/psmgeelen/projecttea
- Arseny Starostin: LinkedIn and Github