Building a Kettle Manager: Raspberry Pi, Machine Learning, and 3D Printing

Pierre Jacquier
Zero to Product!
Published in
16 min readJul 29, 2020

--

I’ve got a cool kettle. Many people have got a cool kettle. It boils up water in no time. Yet if you do your tea properly, you know that fully boiled water at 100 °C is going will literally ruin the fragile green tea leaves.

It’s been very common lately to see cheaper and cheaper electrical kettles that do temperature management. They work wonders, and I would really like to have one.

But there’s one problem. What if I don’t want to throw mine away?

Yes, I could try to sell it. Yes, I could forget about the $30 it cost me three years ago. Yes, I could throw it away and forget about the environmental take it had when produced, and will have when destroyed.

Better question: could we, starting from zero, create a product to actually make it smart, and get the temperature-managing electrical kettle to beg for it? Let’s call it, Kettle Manager!

TL;DR + Prefer things in motion? 📹 YouTube Video

0. User Requirements

A great way to start would be to put together a list of the cool stuff the product should allow for:

  1. Boiling water to the specific temperature,
  2. Remaining non-intrusive and non-breaking.

Let’s dive in. Requirement 1 is the primary purpose of the product, nothing to explain here. Requirement 2 is maybe a stretch at this point, but I need to mention it. I don’t want to mess with my kettle, and neither do you. It needs to be completely operable on its own. Let the poor creature live, please!

1. The Prototype: Raspberry Pi and Machine Learning

The Full Prototype, with the Raspberry Pi at its core, and the various modules

1.0. Components

We start with a Raspberry Pi 2, which was laying around. It could very well be any Raspberry Pi, provided it has WiFi support (here with a cheap dongle).

We’ve used mini-breadboards (yellow, green, red, and blue) for specific components, which is nice for visual organization.

The key component is the temperature sensor, wired to the green breadboard, which is a waterproof cable version of the common DS18B20, easy to use with its three wires with DIY boards like the Pi.

In order to handle user interaction, an LCD display, wired to the yellow breadboard, has been used (because it was laying around again, DIY spirit folks). It is controlled by a rotary encoder, a small electronic component that allows for scrolling and clicking, handy for menu navigation.

The last step is the blue relay, wired to the blue breadboard, shown in a reused (which was laying around) 3D-printed enclosure, controlling a vandalized grounded extension cord (orange), to which we plug the kettle.

The red breadboard handles power inputs, namely the 3.3V used for all modules except the display (which uses 5V).

Summary of our prototype’s Bill of Materials (BOM):

1x Raspberry Pi (WiFi-enabled)

1x Micro SD

4x mini-breadboard

1x waterproof temperature sensor DS18B20

1x 4.7K resistor

A few jumper wires

1x “blue relay” SRD-05VDC-SL-C

1x grounded extension cord

1.1. Preparing our Compute Module

Let’s first install the firmware of the Raspberry Pi. Grab the new automated Raspberry Pi Imager from the official website (available for Windows, macOS, and Ubuntu). We’ll use RASPBIAN PI OS as the Operating System, and our SD Card was GENERIC MASSST… (you should check the size of it so you don’t end up writing on your hard drive! It’s probably < 100GB). Click WRITE.

Creating the SD Card

Before removing it from your computer, we’ll do the WiFi setup there, so we won’t have to plug it to a display and a keyboard at first boot.

Note: these aren’t totally necessary, you could also use a keyboard and an HDMI display to start the system and graphically configure it.

Let’s perform two useful steps after opening your SD Card (named boot);

  • Create a text file without any extension named ssh at the root of the directory;
Creating the empty ssh file on the SD Card
  • Create a text file without any extension named wpa_supplicant, where we’ll write down your WiFi network security settings, replacing MY_NETWORK_NAME and MY_NETWORK_PASSWORD with their respective values, in quotes, as follows.
Creating the wpa_supplicant file on the SD Card
country=us
update_config=1
ctrl_interface=/var/run/wpa_supplicant
network={
scan_ssid=1
ssid="MY_NETWORK_NAME"
psk="MY_NETWORK_PASSWORD"
}
Left from right: wiring the SD card, micro USB cable, and the Wi-Fi dongle.

Now that the SD Card has been prepared, it can be inserted in the dedicated slot of the Raspberry Pi, as per the following figure. You should also connect your WiFi dongle for old models that don’t have it built-in (3+ do), as well as a micro USB power supply (you should check that the current provided is enough, aiming for 2A to ensure the best performance).

The card should boot (with the small lights blinking), and after a while, it should be connected to your Wi-Fi network and should be accessible at the address octopi.local (if not, you should look for its IP address of the form 192.168.X.X on your router's wireless preferences) and the following commands.

$ ssh -p raspberry pi@raspberrypi.local
$ git clone https://github.com/pierremtb/kettle-manager
$ cd kettle-manager
$ pip3 install -r requirements.txt

While the first command connects you to the Pi, with the default password raspberry , the second one clones the source code for the whole product and gets in the directory with the third one. Finally, pre-defined Python 3 dependencies are installed.

We're now fully prepared to look closer at each Module.

1.2. Reading data with the Temperature Module

The temperature sensor chosen for this application is a generic one, with elegant name DS18B20. There exist multiple form-factors for it, and in our application, a waterproof cable-style one is what we need since we’ll dip in the kettle for calibration purposes. Here’s how our version looks.

The waterproof probe on the left, and the three wires on the left, linked to jumper wires for convenience
  • Yellow: ground wire
  • Red: power wire, requires 3.3V
  • Green: data wire

Compared to other simpler devices that may only require to read the LOW/HIGH state of GPIO pins, the thermometer sensor needs to send data through the 1-wire protocol, sending a digital temperature value.

Wiring diagram: power (red) breadboard on top, temperature (green) breadboard on the right.

We need to leverage the “1-wire” interface on the Raspberry Pi, which will happen on the BCM 4 port, as depicted on the diagram as a blue wire. We use an additional mini-breadboard here to prepare power lines so that other modules will be allowed to run afterward. We see on the mini-breadboard on the right (green on the photos) the 4.7K resistor connecting the 3.3V red wire to the blue data wire lire, linked to the output of the sensor. Here is a shot at the wiring.

The real wiring of the temperature module (left) on the green breadboard featuring the resistor.

A specific Python class was written to control the temperature sensor. You don’t have to understand the whole thing, but it goes as follows:

  • At the class initialization, we run two modprobe commands to enable some of the specific 1-wire mode made for this kind of sensor. We then look for a weirdly named directory with glob() in /sys/bus/w1/devices and store it, since it will be the storage location of our temperature;
  • When a reading is requested, we open this directory and make conversions to return a proper reading.

1.3. Showing information with the Display Module

Having the temperature read by the system is nice, but being able to show it is necessary. We make use of a regular 16x2 LCD display, which can be directly controlled by the Raspberry Pi GPIOs without any interface, although it needs a lot of wires.

It’s noteworthy that some of these displays come with an I2C interface and hence require only 4 wires. My second one did so I updated the repository accordingly, but I’ll keep the scripts here untouched.

Wiring diagram: top (yellow) dashboard featuring the 5V power lines and the resistors for contrast tuning

This module isn’t using the 3.3V power (red) breadboard, because unlike all other components, this display requires 5V. We’ll create two power lines directly on the dedicated (yellow) breadboard, as well as an additional resistor line, which will control display contrast.

Wiring the Display module

Ok, let’s jump in the code. This display class actually includes code to create and manage the small user menu, hence its extensive length. However, without diving in too much, let’s understand the main components:

  • We recognize the GPIO pin numbers defined as constant at the top of the file, with RS, E, and DB being the ones controlling the display as defined in the diagram above, as well as POWER for the Switch Module, which we’ll go through later on.
  • __init__ is called to construct the class and sets up the different modules that will be used, namely the Temperature Module (temperature), the Button Module (button), the Switch Module (switch) and the Server Module (model). These last four modules will be detailed in later sections.
  • init_menu creates the different sections and subsections of the menu, that we create reusing code from the library RpiLCDMenu (fork for I2C)
  • The rest of the methods are listeners for evens of this menu and are pretty straightforward.

1.4 User Interaction with the Button Module

Designing a system that has any kind of interaction with a human being is always a compromise between accessibility and the least number of subsystems (buttons, switches, wheels, etc.). In this case, a Rotary Encoder is exactly what we need to both scroll through the options of the menu, and click to select. It is something one can find paired to the same type of display, such as in low-end 3D printers.

Wiring diagram: top-left, our default 3.3V power dashboard (red), right, the 5-pin rotary encoder

As it is displayed on the diagram, connecting this component is straightforward: it needs three data pins, for the actions of rotating clockwise, anti-clockwise and pressing, as well as the two power pins.

Wiring the Button module

For this Button Module, nothing much actually happens in the code, since there's readily available Python package named after its codename, ky040, installed earlier as part of the dependencies.

We can see on top constants defining the GPIO pins used for connecting, namely 5 (green cable), 6 (yellow cable), 13 (blue cable).

1.5 Completing the loop: the Switch Module

Now comes the dangerous section ⚠️: controlling real electricity. Our electric kettle of interest needs 110V of voltage, and it’s not something you want your body to experience (these relays can handle European voltage as well). Make sure to always have everything unplugged from the wall when doing any modifications.

Blue relays are a cheap and efficient solution to make an extension cord controlled by our Raspberry Pi since they provide a 1-pin interface (IN), alongside the usual power pins (VCC and GND).

One can note that on the real current side, there are three inputs, while we only need two to make the “circuit” of the kettle open, either the ground in the extension cord or the positive wire. It’s due to the two different choices that are offered to us:

  • Normally open: if there’s no current applied to the IN pin, the current will not flow between the two inputs;
  • Normally closed: if there's no current applied to the IN pin, the current will flow between the two inputs.

For both security reasons and practical purposes in our intent, we want to use the Normally closed state. We cracked open a grounded extension cord for this and screwed the two wire-sections in as on the following picture.

Wiring diagram: bottom-right, the blue relay, and top-right, the blue breadboard with the NPN transistor

However, it’s not possible to correctly control the switch by directly wiring the IN pin to a GPIO pin of the Raspberry Pi as one would expect, because the voltage provided isn’t high enough to fully reach the threshold. A workaround involves an NPN transistor controlling a full 3.3V power line drawn from the Pi, which will trigger the threshold, yet it will be the NPN that will be controlled by the GPIO.

Wiring the Power module. It sits in an old 3D-printed case for additional security while testing

The code for this Switch Module is dead simple, just a matter of turning on and off one GPIO pin, as follows.

1.6 Predicting the boiling time: intelligent cloud software

Keeping our kettle unharmed and able to work on its own is our top priority in this project. There could have been multiple ways in which a temperature sensor could have been used to determine the boiling time:

  1. by having it directly inside the kettle at all times (it’s waterproof after all);
  2. by having it stuck on the metal side of the kettle, and by finding a way to account for the temperature difference between the inside and outside.

However, both of these approaches come with the caveat of preventing the kettle from working normally. Indeed, 1. would require us to put the sensor in and out each time—or find a way to route it permanently but alterations would need to be made on the kettle side, plus I wouldn’t be comfortable with drinking boiled water with a cheap plastic-covered sensor in it. And 2. would prevent the hot kettle from being taken away to the coffee table, for instance, losing the original flexibility of the dumb but no-so-dumb kettle.

This is why we chose to go for 3., which is:

3. by having it directly inside the kettle once in a while for calibration purposes

If we build a statistical model of the temperature with respect to the boiling time, it’s possible to change the control process in an offline/online way:

  • We enforce an upfront “calibration” step, that would record a cold-water-to-boiling-water transition, and train a model;
  • At normal use time, the user chooses a target temperature, and the model provides the corresponding boiling time.
We choose to construct a model f, linking the boiling time t to the target temperature T and water qty V

While there would be plenty of curve-fitting methods to choose from, a fun exploration that I wanted to make was to use a Neural-Network regression for this problem. Provided the network deep enough, with the help of an activation function, it can approximate virtually any function, and in our case, our function of the target temperature.

Training a Neural Network, even a simple one, is a task a bit too expensive for a Raspberry Pi. Yet, one of the most widespread Deep Learning library, TensorFlow, has something exactly made for this kind of scenario: TensorFlow Lite, a module able to run already-trained models, and is aimed especially at IoT devices such as the Raspberry Pi.

The idea is simple: we offload the computational cost of the model training to a server, after each calibration, and our Raspberry Pi would be just fetching the trained model and evaluating it for new target temperatures.

Here is our small Neural Network model, defined server-side with the regular TensorFlow library. We see that one hidden layer of 64 neurons is used (#15), with a ReLu nonlinearity. The model is trained with Adam optimizer (#19). It’s a very standard setup.

We make use of a simple API set up to make this model accessible on the server, shown as follows. The two important methods are:

  • post_data , used to send calibration data to train the model;
  • get_model , used to retrieve a TensorFlow Lite-converted version of the model, to be used locally by the Raspberry Pi.

This can be set up in minutes on cloud machine providers like AWS or GCP, and both have a free tier to get you started. For instance on AWS LightSail:

Once created, you can use the unmissable “Connect using SSH” button that will open a command line on the server, in which you need to run the following commands.

$ git clone https://github.com/pierremtb/kettle-manager-server
$ cd kettle-manager-server
$ python3 -m pip install requirements.txt
$ python3 src/api.py

On the Raspberry Pi side, we just need one more class, which will define the few code snippets needed to communicate with the server. You’ll need to update BASE_URL accordingly

1.7 The program

Let’s now create a point of entry that will call all of these modules as follows, by convention as a main.py file shown below. We import the main modules–noting that Display encompasses others–and we create an infinite loop with a combination of the infamous while True and time.sleep.

In order to have it running at the board startup (ie. when we power the product), we create a launcher.sh that we execute in /etc/profile.

$ echo "cd kettle-manager//npython3 src/main.py" > ~/launcher.sh
$ sudo echo "sh launcher.sh &" > /etc/profile

Make sure to set headless autologin by running

sudo raspi-config

and choosingBoot Options > Desktop/CLI > Console Autologin > Finish.

2. Creating a Nice Casing: 3D Printing

Now that we have a fully working prototype, let’s think of a packaging that would allow it to be used in our kitchen, and not just in an electronics lab. While this used to be a challenge, on the knowledge, skills, and cost, both modern Computer-Aided Design software and inexpensive desktop 3D Printing solutions are making this possible for a hobbyist.

2.1 Objectives

They are twofold:

  1. Have a minimal design impact
  2. Fit all the prototype components

While the first one is very understandable, the second one is more of a direction we want to keep in this guide: yes, we want to aim toward a product, but we don’t want to sacrifice the modularity and reusability of the components. If the hobbyist decides that letting the water boil is fine and that those cables and electronics parts have better use elsewhere, then so be it!

2.2 Design

We settled on Autodesk Fusion 360 as our CAD platform, which is cloud-based, multi-purpose, and has a hobbyist free plan, bundling everything we need. It also integrates with Ultimaker Cura, the piece of software we will use to turn the model in a printer-language format.

On top of the objectives we have just discussed, we have to take into account the 3D Printing method used to obtain the parts in the end, which is Fused Deposition Modeling, which has its own constraints such as a 45 degrees maximal angle with the vertical axis for the overhang, if one wants to limit the use of supports.

We settled on a three-part casing, featuring slider joints removing the needs for fasteners. This is just a design decision, linked to the relatively static use of the product and simplicity-seeking.

The “Main” part
The “Front” part
The “Cap” part

Here is a Thingiverse post with the different ready-to-print STL models (alternative link), as well as the full Fusion 360 product with downloadable source files in various formats.

Render of the full product using Fusion 360, cap-less to see the insides

2.3 Print!

We used a Creality Ender 3 printer to manufacture these designs, which reliable and inexpensive for anyone new and even experienced with desktop 3D Printing.

The slicer Ultimaker Cura provides a great interface to transform the STL models to G-Code, the language that industrial machines and our printer speak. Some printers have their own slicing program on board though and can do this step automatically.

Slicing the “Main” part
Slicing the “Front” part
Slicing the “Cap” part

Here are the time-lapses.

After assembling everything, the design becomes a reality. At this point, it feels really good.

3. Going Further: a Product

Would this idea have a place on the market? Impossible to tell, ideas are cheap, it’s good executions that are worth millions.

3.1 The (not so) easy route

Considering that the total BOM (Bill Of Materials) was about $50 for the prototype, we could probably aim at a $9.99 or $19.99 price tag depending on the quality we aim at. It would require to re-engineer the whole system, from creating Printed-Circuit Boards (PCBs) to injection molds design, or much other Design For Manufacturing (DFM) constraints.

To be sustainable and avoid recurring costs, we would need to take the learning aspect back offline, which wouldn’t be that hard considering the simplicity of the modeling task. However, a simple device like this would be so easy to clone that we would see copycats appearing in a matter of weeks, to impossible prices like $4.99.

While being copied often means you’re onto something, you still need to be able to compete, and a mass-market dumb products won’t drive enough brand-awareness to balance it out.

3.2 The adventurous path

What if we were making more use of the Internet-of-Things (IoT) segment of our Kettle Manager? With it, it would be possible for the products to provide more value than just making boiling time predictions: for instance, tracking hydration would be an interesting direction.

A dedicated app and linked account could indeed record the water you put up for heating and provide you with useful feedback on how much you drink. To really be of value to the user, this data will be exportable to common health platforms that support hydration tracking, such as Apple Health, Samsung Health, or Runtastic.

Additional take: boiling water is mostly used for tea and coffee. Some people want the other way around sometimes, which would be limiting their intake of these delicious beverages. With a tagging system in the app, this product could really be onto something, and with proper marketing and valuable content posted online on health topics, a real brand could emerge.

Combining these aspects with the software and cloud infrastructure needed, this could very well sell at $49, just below the average temperature-controlled kettle, and focus solely on providing value to customers rather on the competition.

Wrapping up

  • Defining user requirements and objectives
  • Day-to-day application of Machine Learning techniques
  • Using Autodesk Fusion 360 as a complete CAD/rendering platform
  • Failing quickly and iterating accordingly with 3D Printing

--

--

Pierre Jacquier
Zero to Product!

Hardware Engineer at @Algolux. Computationally curious.