Together with my partner Maud Bausier, we are making an incubator.
As vegans, tempeh (fermeted food in general) is an important part of our diet. It is full of proteins, macrobiotics and it is delicious.
We started producing our own tempeh when we lived in Amsterdam, where we had a small room dedicated to a boiler, ensuring a constant temperature all year round. But that changed when we moved to Barcelona, where the temperature in the flat is practically the same as the outside temperature, because the windows are almost always open, which involves temperature variations that prevent us from producing the tempeh we love.
That's why we are making an incubator, called Tempeh Machine, to help us ferment our delicious food ourselves in all seasons. Our incubator will be entirely made in a Fab Lab, all sources will be available.
The electronic part of the incubator must remain as simple as possible, to offer the possibility of being understood and modified by others. I don't want to lock the users in a device they don't understand.
It is built as an extra board that comes with a Barduino, allowing it to operate with two 12V outputs and one 5V input.
Components
Barduino
A Barduino, an ESP32 development board made in Barcelona, is used as the brain. This allows me to use a Wifi compatible board with a functional USB connection without having to do it (again) by myself. Moreover, it allows me to design a shield (something I've never done before) and to participate in an open-source project that I'd like to support.
Humidity and temperature sensor
A DHT11 humidity and temperature sensor provides information on what is happening in the incubator. I use the DHT11 mainly because it is available in the laboratory. I am not entirely satisfied with this sensor because it is slow and sometimes skips some data. It is clearly sufficient for this project because I don't need a high efficiency sensor, but it is not ideal.
Heating pad
A heating pad (datasheet) is used to warm up the temperature inside the incubator. When supplied with 12V, it can reach up to 110°C. It is not necessary to reach this temperature, but it will allow us to have the desired temperature even if the incubator is not fully insulated.
Fan
A 12V fan is used to distribute the heat evenly inside the incubator, or to try to cool it down in case it gets too hot (which could easily happen in the Barcelona sun).
RGB LED
An RGB LED is used to communicate basic information to the user. Does the incubator heat or cool? Has it reached the desired temperature? etc.
Schematics
Interesting points
A voltage regulator is used to convert 12V to 5V (which is used by the sensor and the Barduino)
A small mosfet and two resistors are used as a level shifter to convert 3.3V to 5V on the line to the sensor, so it only speaks in 5V.
Big mosfets are used on the 12V lines to let the current flow to the two outputs, the fan and the heating pad.
A diode is used on the fan line to ensure that the current won't fly back on the unwanted direction when the motor stops, thus protecting the circuit.
A OΩ resistor has been added to act as a jumper to facilitate the PCB design.
known errors
the GPIO 34, 35, 36, 39 on the ESP32 are only inputs (source) and therefore can't be used for the fan or the heating pad. I discovered this only after the fabrication, I had to add an extra cable from an empty pin to the heating pad line (where was the error). Good to know for next time.
PCB design
Fabrication
Incubator shield
The SRM-20 milling machine wasn't properly calibrated when I used it because it had just received a new motor. The quality of my milling is therefore not the best, but after a close check with a multimeter, I can confirm that all the tracks are correctly connected.
Barduino
The files to make the barduino can be found on its gitlab repository.
Fab Lab Barcelona ordered several PCBs from their PCB design in order to speed up the production of the Barduino (which is used in various projects). Only the assembly, the soldering of the components, is necessary to make it work.
To make sure I understand how a web interface is made via an ESP32, I started with a very basic example. The only thing this minimal example will do is to light on and off the RGB LED connected to the Barduino (ESP32) through the incubator shield I designed via a web interface accessible from any browser (desktop and mobile).
Key elements
Librairies
Include the librairies: Arduino framework, AnalogWrite to manipulate analog output with the ESP32 and Wifi, the one that interests us here.
This code is then used to initialize a connection to the address 192.168.1.118. This IP address is accessible to all devices connected to the same Wifi network.
Information will travel via the URL that we send from one side and receive on the other.
For example, a button will add /?RED=ON to the end of our url 192.168.1.118, forming a 192.168.1.118/?RED=ON that we can parse to do things in our code.
void buildPage()
{
WiFiClient client = server.available();
if (client)
{
Serial.println("New Client is requesting web page");
String current_data_line = "";
while (client.connected())
{
if (client.available())
{
char new_byte = client.read();
Serial.write(new_byte);
header += new_byte;
}
}
}
}
If else conditions
Depending on what we get in the header, we can switch the LED on and off.
if (header.indexOf("GET /RED=ON") >= 0)
{
Serial.println("LED is red");
active_color = "red";
rgbLed(100, 0, 0);
}
else if (header.indexOf("GET /?GREEN=ON") != -1)
{
Serial.println("LED is green");
active_color = "green";
rgbLed(0, 100, 0);
}
else if (header.indexOf("GET /?BLUE=ON") != -1)
{
Serial.println("LED is blue");
active_color = "blue";
rgbLed(0, 0, 100);
}
Build the page
To finally build our HTML page with the variables and buttons that allow us to change the colour of the LEDs.
client.println("<!DOCTYPE html><html<");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head>");
client.println("<body><h1>ESP32 minimal example</h1>");
client.println("<p>The RGB led is currently <b>" + active_color + "</b>. Click one of the following button to change its color.</p>");
client.println("<form>");
client.println("<button name=\"RED\" value=\"ON\" type=\"submit\">RED</button>");
client.println("<button name=\"GREEN\" value=\"ON\" type=\"submit\">GREEN</button>");
client.println("<button name=\"BLUE\" value=\"ON\" type=\"submit\">BLUE</button>");
client.println("</form>");
client.println("</body></html>");
Source code
#include <Arduino.h>
#include <analogWrite.h>
#include <WiFi.h>
// Wifi
const char *ssid = "********";
const char *password = "********";
WiFiServer server(80);
String header;
// LED Constants
#define led_red 33
#define led_green 25
#define led_blue 26
// LED Variables
String active_color = "off";
void rgbLed(int red, int green, int blue)
{
// The values must be reversed because the LED must be pulled down to operate
analogWrite(led_red, map(red, 0, 255, 255, 0));
analogWrite(led_green, map(green, 0, 255, 255, 0));
analogWrite(led_blue, map(blue, 0, 255, 255, 0));
}
void initWiFi()
{
Serial.println("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected successfully");
Serial.print("Got IP: ");
Serial.println(WiFi.localIP());
server.begin();
Serial.println("HTTP server started");
delay(100);
}
void buildPage()
{
WiFiClient client = server.available();
if (client)
{
Serial.println("New Client is requesting web page");
String current_data_line = "";
while (client.connected())
{
if (client.available())
{
char new_byte = client.read();
Serial.write(new_byte);
header += new_byte;
if (new_byte == '\n')
{
if (current_data_line.length() == 0)
{
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
if (header.indexOf("GET /RED=ON") >= 0)
{
Serial.println("LED is red");
active_color = "red";
rgbLed(100, 0, 0);
}
else if (header.indexOf("GET /?GREEN=ON") != -1)
{
Serial.println("LED is green");
active_color = "green";
rgbLed(0, 100, 0);
}
else if (header.indexOf("GET /?BLUE=ON") != -1)
{
Serial.println("LED is blue");
active_color = "blue";
rgbLed(0, 0, 100);
}
client.println("<!DOCTYPE html><html<");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head>");
client.println("<body><h1>ESP32 minimal example</h1>");
client.println("<p>The RGB led is currently <b>" + active_color + "</b>. Click one of the following button to change its color.</p>");
client.println("<form>");
client.println("<button name=\"RED\" value=\"ON\" type=\"submit\">RED</button>");
client.println("<button name=\"GREEN\" value=\"ON\" type=\"submit\">GREEN</button>");
client.println("<button name=\"BLUE\" value=\"ON\" type=\"submit\">BLUE</button>");
client.println("</form>");
client.println("</body></html>");
client.println();
break;
}
else
{
current_data_line = "";
}
}
else if (new_byte != '\r')
{
current_data_line += new_byte;
}
}
}
header = "";
client.stop();
Serial.println("Client disconnected.");
}
}
void setup()
{
Serial.begin(9600);
delay(500);
pinMode(led_red, OUTPUT);
pinMode(led_green, OUTPUT);
pinMode(led_blue, OUTPUT);
rgbLed(0, 0, 0);
initWiFi();
}
void loop()
{
buildPage();
}
I decided to go screenless for this project, and to use the screen that we already have in our pocket: the one from our phone. This choice is motivated by the resource I have at my disposal. Ideally, in the next version, I would add a tiny screen to make the incubator totally independent of other technologies. I don't want to force the use of a smartphone (because I would like to stop using mine).